【发布时间】:2016-07-29 09:11:38
【问题描述】:
我一直在学习 JavaFX 的任务,并使用它们使用 Platform.runLater 或任务的 updateValue 方法等与应用程序线程通信。但是,我的 Task 需要知道用户何时按下GUI 因为这可能会更改任务的updateValue 方法需要返回的值。我该怎么做呢?我知道如何响应单线程应用程序上的按钮按下事件,但不确定如何以线程安全的方式处理它。
更新:
这是我目前所拥有的,这是实现按钮事件的明智方式吗?
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.PixelFormat;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.control.Button;
import java.nio.IntBuffer;
public class TaskExample extends Application {
private Canvas canvas;
private PixelWriter pixel_writer;
@Override
public void start(Stage primaryStage) throws Exception {
canvas = new Canvas(256, 256);
pixel_writer = canvas.getGraphicsContext2D().getPixelWriter();
MyTask task = new MyTask();
task.valueProperty().addListener((c) -> {
if(task.getValue() != null) {
update(task.getValue());
}
});
Thread thread = new Thread(task);
thread.setDaemon(true);
thread.start();
Button button = new Button("Button 1");
// On the button click event it calls the eventFired() method
button.setOnAction((event) -> {
task.eventFired();
});
Pane pane = new VBox();
pane.getChildren().addAll(canvas, button);
primaryStage.setScene(new Scene(pane));
primaryStage.show();
}
public void update(IntBuffer data) {
pixel_writer.setPixels(
0,
0,
256,
256,
PixelFormat.getIntArgbInstance(),
data,
256
);
}
public static void main(String[] args) {
launch(args);
}
class MyTask extends Task<IntBuffer> {
public void eventFired() {
System.out.println("Event fired");
}
public void update(IntBuffer data) {
updateValue(data);
}
@Override
protected IntBuffer call() throws InterruptedException {
while(true) {
for (int i=0; i<3; i++) {
Thread.sleep(1000);
IntBuffer data = IntBuffer.allocate(256*256);
for(int j=0; j<256*256; j++) {
switch(i) {
case 0: data.put(0xFF0000FF); break;
case 1: data.put(0xFF00FF00); break;
case 2: data.put(0xFFFF0000); break;
}
}
data.rewind();
update(data);
}
}
}
}
}
【问题讨论】:
-
您发布的代码没有问题,但实际上并没有按照您的描述进行:即两个线程不交互。当您按下按钮时,任务将在 FX 应用程序线程上向控制台显示一条消息。但是没有任何改变会影响后台线程上发生的事情。因此,如果您想问“这行得通吗”,您需要实际展示一些符合您描述的代码。
-
啊,我没有意识到他们没有互动。如何在后台线程上运行
eventFired方法? -
你不能在后台线程上运行它。但是大概只是向控制台发送消息并不是您真正想要做的。你想做一些改变
call方法中发生的事情的事情(除了你在这个阶段没有人知道),不是吗? -
我想要实现的是让
call方法知道按钮已被按下。因此,根据您对@Eudy Contreras 的回答的评论,您会建议原子变量和侦听器是要走的路吗? -
我认为以线程安全的方式更改变量的状态是您想要做的。原子引用是使该线程安全的一种简单方法(但可能有点矫枉过正,具体取决于细节)。 JavaFX 属性是单线程的,因此在此处使用这些属性和侦听器将非常困难(充其量)。
标签: java multithreading user-interface javafx concurrency