[英]JavaFX show AnchorPane from Thread
我正在尝试创建以下概念:每当特定屏幕启动时启动一个线程。 该线程应该收到一条名为“标签”的消息,该消息尚未工作,因此我对其进行了硬编码。 然后根据标签的验证显示一个 AnchorPane:showError 或 showValid 函数。 但是,应用程序首先运行该函数,然后显示 AnchorPane 和更新后的 ListView。
我想在特定屏幕启动时启动以下线程。
public class RFIDThread extends Thread{
private static final Logger logger = Logger.getLogger(RFIDApplication.class);
/**
* The incoming data stream from the LLRP reader connection
*/
private DataInputStream inStream = null;
/**
* The socket for the connection to the LLRP Reader
*/
private Socket socket = null;
/**
* A queue to store incoming LLRP Messages
*/
private LinkedBlockingQueue<LLRPMessage> queue = null;
private String[] found_tags = new String[5];
private JSONArray valid_tags;
private TagsListController controller;
/**
* Thread for constant reading of the stream
*
* @param socket
* @param controller
* @param tags
* @param orderNumber
* @throws java.io.IOException
*/
public RFIDThread(Socket socket, TagsListController controller, JSONArray tags, String orderNumber) throws IOException {
this.socket = socket;
this.controller = controller;
this.queue = new LinkedBlockingQueue<LLRPMessage>();
try {
this.inStream = new DataInputStream(socket.getInputStream());
} catch (IOException e) {
logger.error("Cannot get input stream", e);
}
valid_tags = tags;
found_tags[0] = "aga9jrjahr";
found_tags[1] = "agahs4suj";
found_tags[2] = "a79gtvaTGBQG";
found_tags[3] = "at3anit08av9agq4";
//found_tags[4] = "4a05355d0000000000017cc0";
//start();
}
@Override
public void run()
{
super.run();
if (socket.isConnected()) {
for (String found_tag : found_tags) {
Integer index = valid_tags.indexOf(found_tag);
if (index > 0) {
Platform.runLater(() -> {
controller.showValid(found_tag);
});
} else {
Platform.runLater(() -> {
controller.showError(found_tag);
});
}
}
}
}
}
线程应该运行函数:showError 或 showValid 基于它接收到的标签。 目前我有一些硬编码的标签设置都是无效的,所以它应该运行 showError() 函数。 该功能:将标签添加到ListView,将标签设置为标签文本,显示AnchorPane,休眠1秒,隐藏AnchorPane,然后休眠1秒。 在此之后,必须处理下一个标签。
/**
* Display red screen
* @param tag
*/
public void showError(String tag) {
this.found_tags_list.getItems().add(tag);
this.errorTag.setText(tag);
System.out.println(errorTag.getText());
this.errorPane.setVisible(true);
pause(1000);
this.validPane.setVisible(false);
pause(1000);
}
您没有发布pause()
方法的代码,因此我假设它执行类似Thread.sleep(...)
并适当处理中断的异常。 即我将假设你有类似的东西:
public void pause(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException exc) {
Thread.currentThread().interrupt();
}
}
showError()
方法正在(显式)在 FX 应用程序线程上执行。 该线程还负责呈现 UI。 因此,在执行showError()
方法时无法重绘 UI(因为单个线程不能同时做两件事:这基本上是“线程”的定义)。
所以阻塞FX Application Thread总是一个错误,因为它使UI无响应并阻止它被绘制。
如果您已经在 FX 应用程序线程上,并且想要安排一些代码在将来执行,您可以使用PauseTransition
来做到这PauseTransition
。 所以代替
this.errorPane.setVisible(true);
pause(1000);
this.validPane.setVisible(false);
你可以做
this.errorPane.setVisible(true);
PauseTransition pause = new PauseTransition(Duration.millis(1000));
pause.setOnFinished(e -> this.validPane.setVisible(false));
pause.play();
该方法中的第二次pause
意义不大。 它只是暂停 FX 应用程序线程,然后该方法退出,因此无论如何它都没有等待。
如果这个想法是让后台线程在那个时候暂停,你应该在后台线程上调用pause()
。 (显然,在 FX 应用程序线程上调用它不会使后台线程暂停。)
所以我认为你的代码应该是这样的:
public class RFIDThread extends Thread {
// ...
@Override
public void run() {
super.run();
if (socket.isConnected()) {
for (String found_tag : found_tags) {
Integer index = valid_tags.indexOf(found_tag);
if (index > 0) {
Platform.runLater(() -> controller.showValid(found_tag));
} else {
Platform.runLater(() -> controller.showError(found_tag));
}
pause(2000);
}
}
}
}
请注意,我在这里猜测的目的是让您的后台线程在您显示的窗格再次隐藏后暂停(大约)一秒钟,这意味着它总共需要暂停两秒钟。
在控制器中,你做
public void showError(String tag) {
this.found_tags_list.getItems().add(tag);
this.errorTag.setText(tag);
System.out.println(errorTag.getText());
this.errorPane.setVisible(true);
PauseTransition pause = new PauseTransition(Duration.millis(1000));
pause.setOnFinished(e -> this.validPane.setVisible(false));
pause.play();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.