JavaFX显示来自线程的锚烷

JavaFX显示来自线程的锚烷,java,multithreading,javafx,Java,Multithreading,Javafx,我试图创建以下概念:每当启动特定屏幕时启动一个线程。线程应该会收到一条称为标记的消息,该消息尚未工作,因此我对其进行了硬编码。 然后根据标签的验证显示一个锚烷:showError或showValid函数。但是,应用程序首先运行函数,然后显示AnchorPane和更新的ListView 每当一个特定的屏幕启动时,我想启动以下线程 public class RFIDThread extends Thread{ private static final Logger logger = L

我试图创建以下概念:每当启动特定屏幕时启动一个线程。线程应该会收到一条称为标记的消息,该消息尚未工作,因此我对其进行了硬编码。 然后根据标签的验证显示一个锚烷: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);
                        });
                    }
                }
            }
       }
}

您没有发布暂停方法的代码,所以我假设它执行类似于Thread.sleep的操作。。。并适当地处理中断的异常。也就是说,我假设你有这样的东西:

public void pause(int millis) {
    try {
        Thread.sleep(millis);
    } catch (InterruptedException exc) {
        Thread.currentThread().interrupt();
    }
}
正在FX应用程序线程上显式执行淋浴ROR方法。该线程还负责呈现UI。因此,在执行淋浴ROR方法时无法重新绘制UI,因为单个线程不能同时执行两件事:这基本上是线程的定义

因此,阻止FX应用程序线程始终是一个错误,因为它会使UI无响应并阻止绘制它

如果您已经在FX应用程序线程上,并且希望安排一些代码在将来执行,那么可以通过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();
这种方法中的第二个停顿没有什么意义。它只是暂停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();
}

如果暂停。。。按照我的假设,您正在阻止FX应用程序线程,因为。。。在该线程上执行。这将阻止用户界面呈现,直到整个淋浴。。。方法(包括其暂停)已完成。如果要在暂停后执行基于UI的操作,请使用。现在还不清楚第二次暂停的目的是什么,因为之后什么也没有发生。另外,您可能是指.errorPane.setVisiblefalse;?您还可以将暂停移动到后台线程,并在控制器中使用hideError和hideValid方法,您可以通过Platform.runLater调用这些方法。。。从该线程。方法在控制器中,这就是为什么我将控制器传递给线程,以便它可以调用这些方法。这与我的评论有什么关系?当我回到我的计算机时。但我很难理解为什么不能按照简单的指令将暂停移到后台线程。
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();
}