[英]JavaFX - Thread hangs, and I can't figure out how to run my loop outside the UI thread
朋友。 这是stackoverflow的新功能,也是JavaFX的新功能。 抱歉,如果我弄乱了任何命名法,并且有点冗长,但是我确实将代码缩减为一个最小的“有效”示例。 (下面的代码会挂起,除非您注释掉while循环,如代码本身所述)
我试图弄清楚如何使Slider
在单击“唤醒”按钮后连续更改其值,并在单击“睡眠”按钮后停止更改值。 为了便于讨论,可以说它随机将值更改为0到99之间的整数。
从我读这么远 (我已经读了很多,但这些都是最近的两个例子),看来我应该能够使用Platform.runLater()
或updateMessenger()
来避免运行无限-直到UI线程上的my-sleep-button-breaks-it循环为止。 到目前为止,我没有实现前者,但是我仍然不确定如何实现后者。
我还尝试学习有关属性绑定的信息,以便可以在更改中间变量(我称为state
并创建)时在UI线程中更改Slider.valueProperty
(在UI线程中更改UI元素是有意义的...对吗?)。从背景线程上的stateObject
类中stateObject
。 后台线程计算完要提供给滑块的值后,它将更改state
的值,该值绑定到Slider
的值。 我以为将值计算分为后台线程,将Slider
值更改为UI线程可以解决问题,但我一直遇到挂断或臭名昭著的IllegalStateException
异常, Not on FX application thread
我不完全确定Platform.runLater()
魔术应该如何工作,但是无论我在其中运行可运行接口还是在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;
}
}
}
您不需要具有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();
}
Button
onAction
是在JavaFX Application Thread
上处理的,在任何情况下,除非它是它自己的内部结构,否则我们都不希望在该线程上运行无限循环,因为该循环只会使该线程挂起。 因此,我们创建了一个new Thread t
,该new Thread t
将具有该循环,并且在其主体中将调用JavaFX Application Thread
以提交更改。 收集到的信息,必须在JavaFX Application Thread
上对UI / JavaFX属性进行更改。 Platform.runLater( "some code" )
意味着将来将在JavaFX Application Thread
上(如果线程不忙,几乎是立即执行)执行“某些代码”。
至于此类应用程序的设计,我建议您看看AnimationTimer
- https: //docs.oracle.com/javase/8/javafx/api/javafx/animation/AnimationTimer.html或Timeline
- https:/ /docs.oracle.com/javase/8/javafx/api/javafx/animation/Timeline.html 。 它们都在JavaFX Application Thread
上运行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.