[英]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.