朋友。 stackoverflow的新功能,此处以及JavaFX。抱歉,如果我搞砸了任何术语,如果这有点啰嗦,但我确实把我的代码简化为最小的工作"例。 (除非你注释掉while循环,否则下面的代码会挂断,如代码本身所述)
我试图弄清楚如何在点击"唤醒"后不断改变其值Slider
。单击" sleep"按钮并停止更改值按钮。为了论证,假设它随机地将值改变为0到99之间的整数。
从我read far所以match
(我已经阅读了很多,但这些是最近的两个例子),似乎我应该可以使用Platform.runLater()
或updateMessenger()
以避免在UI线程上运行无限直到我的睡眠按钮 - 中断循环。到目前为止,我没有实施前者,我仍然不确定如何实施后者。
我还尝试了解属性绑定,以便我可以在更改中间变量时更改UI线程中的Slider.valueProperty
更改(更改UI线程中的UI元素有意义......对吗?)我在后台线程上调用state
并从类stateObject
创建。在后台线程计算我想要给滑块的值后,它会更改state
的值,该值绑定到Slider
的值。我认为将值计算分离为后台线程并且Slider
值更改为UI线程可以解决问题,但我不断得到挂起或臭名昭着的IllegalStateException
异常,Not on FX application thread
我并不完全确定Platform.runLater()
魔法是如何工作的,但我仍然得到一个挂机,无论我在其中运行我的runnable接口还是Thread()
。
对于为什么这些尝试失败/如何使事情有效的任何帮助或解释将不胜感激。
干杯, 麦克
import javafx.application.*;
import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.layout.*;
import javafx.scene.control.*;
import javafx.geometry.*;
//Not sure which of these, if any, I actually need
import javafx.event.*;
import javafx.concurrent.*;
import javafx.beans.property.*;
public class MWE extends Application {
//Main method
public static void main(String[] args) {
launch(args);
}
//Class fields
Button sleepBtn, wakeBtn;
Slider displaySldr;
boolean wakeful = true;
//state property class
class stateObject {
//Store the property
private DoubleProperty state = new SimpleDoubleProperty();
//Define getter for property value
public final double getState() {
return state.get();
}
//Define setter for property value
public final void setState(double val) {
state.setValue(val);
}
//Define getter for property itself
public DoubleProperty stateProperty() {
return state;
}
}
//Create state
stateObject state = new stateObject();
//Start method
@Override
public void start(Stage primaryStage) {
//Create top-level pane to store nodes into for the scene
VBox mainPane = new VBox(20);
mainPane.setAlignment(Pos.CENTER);
//Create buttons
sleepBtn = new Button("Sleep");
sleepBtn.setOnAction(e -> NPSleep());
wakeBtn = new Button("Wake");
wakeBtn.setOnAction(e -> NPWake());
//Lay out buttons
VBox buttonsBox = new VBox(10);
buttonsBox.getChildren().addAll(wakeBtn,sleepBtn);
buttonsBox.setAlignment(Pos.CENTER);
//Create slider to be change continuously by clicking wakeBtn once
//Slider should stop changing when sleepBtn is clicked
displaySldr = new Slider(0,100,50);
displaySldr.setMajorTickUnit(25);
displaySldr.setMinorTickCount(24);
displaySldr.setSnapToTicks(true);
displaySldr.setShowTickMarks(false);
displaySldr.setShowTickLabels(true);
//Make property event. When 'state' changes, change displaySldr value
state.stateProperty().addListener(
(observable,oldvalue,newvalue) ->
displaySldr.setValue(newvalue.intValue())
);
//Organize labels and sliders
VBox LSPane = new VBox(10);
LSPane.getChildren().addAll(displaySldr);
LSPane.setAlignment(Pos.CENTER);
//Organize sub-panes into top-level pane, mainPane
mainPane.getChildren().addAll(LSPane,buttonsBox);
//Set the scene
Scene mainScene = new Scene(mainPane);
//Set the stage
primaryStage.setTitle("oh god please work");
primaryStage.setScene(mainScene);
primaryStage.show();
}
private void NPWake() {
Runnable wakeyWakey = () -> {
while (wakeful == true) { //Commenting out the while loop and
//leaving the command allows program to run fine
//but slider changes only once, not continuously
state.setState( Math.floor(Math.random()*100) );
try{
Thread.sleep(300);
} catch (InterruptedException ie) {
}
}
};
Platform.runLater(wakeyWakey);
// Thread wakeThread = new Thread(wakeyWakey); //
// wakeThread.start(); // This doesn't work either
}
private void NPSleep() {
if (wakeful == true) {
wakeful = false;
}
}
}
答案 0 :(得分:1)
您不需要State Object
,因为您仍然必须更新JavaFX Application Thread
上的值,因此它无法创建此类对象。您可以删除所有State Object
相关代码。以下代码是您的解决方案的修复程序:
private void NPWake() {
Thread t = new Thread(() -> {
while (wakeful) {
try {
Platform.runLater(() -> {
displaySldr.setValue(Math.floor(Math.random() * 100));
});
Thread.sleep(300);
}
catch (Exception e) {}
}
});
t.start();
}
在onAction
处理Button
的{{1}}并且在任何情况下我们都不希望在该线程上运行无限循环,除非它是它自己的内部,因为循环将简单地挂起那个帖子。因此,我们创建一个JavaFX Application Thread
,它将具有该循环,并在其正文中调用new Thread t
来提交更改。如您所收集的,必须在JavaFX Application Thread
上更改UI / JavaFX属性。 JavaFX Application Thread
表示“某些代码”将在未来某个时间点在Platform.runLater( "some code" )
上执行(如果线程不忙,几乎立即执行)。
至于此类应用程序的设计,我建议您查看JavaFX Application Thread
- https://docs.oracle.com/javase/8/javafx/api/javafx/animation/AnimationTimer.html或AnimationTimer
- https://docs.oracle.com/javase/8/javafx/api/javafx/animation/Timeline.html。它们都运行在Timeline
。