当前位置: 首页 > 知识库问答 >
问题:

根节点更改时后台线程不关闭[javaFX]

宗翔宇
2023-03-14

我正在创建一个javafx程序,该程序的导航菜单通过更改场景的根来工作。根都是从Pane类继承的。有些窗格具有它们运行的后台线程。但是,当根窗格被事件处理程序更改时,窗格会切换,但后台线程不会停止。这会导致线程读取NFC时出现问题,并导致多个线程尝试从NFC读取器读取。
如何关闭后台线程?(从创建线程的窗格外部),还是需要以不同的方式设置线程。(线程设置为Daemon)。线程是在窗格构造函数中创建的,如下所示:(我曾假设,由于它们属于窗格,当窗格被切换时,线程将停止,但事实并非如此)。

  Runnable r = new Runnable() {
        @Override
         public void run () {
             boolean cont = true;
             while(cont){

                try {
                    NFCcard create1 = new NFCcard();

                    String staffID=create1.getCardID().toString();
                    staffID = staffID.replaceAll("\\D+","");
                    signIn.setText("Welcome "+getUserName(staffID)+getPhotoSrc(create1.getCardID().toString()));

                    Thread.sleep(1000);

                } catch (CardException e) {


                } catch (InterruptedException e) {

                }
                signIn.setText("Scan your card to sign in/out");
                if(getScene().getRoot().isDisable());
                    cont=false;
             }

            }};

     Thread nfcCheckThread = new Thread(r);
     nfcCheckThread.setDaemon(true);
     nfcCheckThread.start();

我以静态的方式切换窗格,如下所示:(这些方法在自己的类中)。

   public static void homeButtonhandler(Stage stage){ 
     HomePane mainPane1=new HomePane(stage, new HomeContent(stage));
     stage.getScene().setRoot(mainPane1);
     }
 public static void adminButtonhandler(Stage stage){

      DialogBox dialog = new  DialogBox();

      try{
        Optional<String> result = dialog.showAndWait();
        if (result.get().equals("115")){
            AdminPane adminPane1 = new AdminPane(stage,new Content(stage));
            stage.getScene().setRoot(adminPane1);
            }}

        catch(NoSuchElementException Exception){

        }


 }

public static void workingTodayButtonhandler(Stage stage){
     //TODO trying to make the content change when when buttons are clicked

     HomePane mainPane2=new HomePane(stage,new WorkingTodayContent(stage));

     stage.getScene().setRoot(mainPane2); 
//  System.out.println(mainPane2.content);

 }

第一个呼叫是:

HomePane myPane=新HomePane(初级阶段,新HomeContent(初级阶段));

    Scene homeScene = new Scene (myPane);

    primaryStage.setMinHeight(1000);
    primaryStage.setMinWidth(1700);

    primaryStage.setScene(homeScene);


    primaryStage.show();

共有1个答案

胡国兴
2023-03-14

正如你所说:

有些窗格具有它们运行的后台线程。

假设您在自己的pane实现中创建了这些线程。我将向您展示一个包含抽象类的解决方案,您的每个窗格(或至少作为根插入的窗格)都应该扩展这个抽象类。如果你没有,我强烈建议你这样做。但是,您没有提供关于这些窗格的太多信息,因此我将把我的答案集成到代码中(如果您决定遵循它的话)。

public abstract class OwnPane extends Pane {
    protected volatile boolean isRoot = false;

    public void setAsRoot(){
        isRoot = true;
    }

    public void unsetAsRoot(){
        isRoot = false;
    }
}

现在,您可以创建线程,最好是在ownPane或它的子类中,使用activatethread-方法,例如:

public void activateNFCThread(){
    Runnable r = new Runnable(){
            @Override
            public void run () {
                 while(isRoot){
                      // what the thread has to do ...
                 }
            }
    };
    Thread nfcCheckThread = new Thread(r);
    nfcCheckThread.setDaemon(true);
    nfcCheckThread.start();
}

现在我可以解释为什么必须使用volatile关键字:字段isroot将被不同的线程使用。通过volatile关键字,我们确保所有线程都将访问同一个“变量”(否则每个线程出于性能原因将有自己的版本)。
线程是在ownpane(或子类)的方法中创建的,这一事实允许从runnable对象中访问isroot字段。在ownpane的子类中,甚至可以重写setasroot方法,以便在调用setasroot方法时(如果需要)直接启动NFS线程:

public class PaneWithNFCReader extends OwnPane {
    @Override
    public void setAsRoot(){
         super.setAsRoot();
         activateNFCThread();
    }
}

最后,您可以使用以下方法更改舞台中场景的根窗格:

// All your methods regarding stage changes are static, so I'll leave this one static too
public static void changeRoot(Stage stage, OwnPane newRoot){
    OwnPane oldStage = (OwnPane)stage.getScene().getRoot();
    oldStage.unsetAsRoot();
    Platform.runLater(() -> {   //Platform.runLater to be sure the main thread that will execute this 
                                //(only main thread is allowed to change something in the JavaFX nodes)
        stage.getScene().setRoot(newRoot);
        newRoot.setAsRoot();
    });
}
 类似资料:
  • 我是XSLT新手。我想根据其他子节点的条件更改XML中的根节点。但子节点始终保持不变。例如,我有以下XML: 我喜欢将XML更改为: 这意味着依赖于<代码> 我不想在每个<代码>

  • 问题内容: 我有一个Python程序,当我使用退出应用程序时 ,脚本不会关闭。我的过程仍显示在运行的过程中。 为什么python线程不能关闭? 问题答案: 您需要将该线程设为守护程序线程。为此,请在调用线程的init之后添加以下行 当只有守护程序线程处于活动状态时,程序将退出,主线程当然是非守护程序的

  • 我目前正在研究Hazelcast,将其用作集群中的消息队列和共享内存存储。 我想知道如何处理最后一个节点下降的情况。我想坚持所有hazelcast管理的数据,队列,等磁盘的能力,以再次启动在以后的时间。 MapStore和MapLoad功能看起来很有趣,但何时使用?文档中说它可以在需要的时候使用,但我只需要在关闭最后一个节点时使用它。在正常操作期间,不需要保留所有数据。 此外,磁盘写入应该在最末尾

  • 问题内容: 我有一个在Websphere Application Server 6.0(WAS)内的Websphere Portal Server中运行的应用程序。在此应用程序中,由于需要花费很长时间才能完成一项特定功能,因此我将触发执行此操作的新线程。这个新线程从Hibernate打开一个新的Session,并开始使用它进行数据库事务。有时(无法看到模式),线程内的事务工作正常,并且该过程成功完

  • 问题内容: 我目前正在使用两个控制器类。 在Controller1中,它创建一个新的阶段,该阶段在主要阶段的顶部打开。 现在,一旦该阶段打开,我希望它在关闭之前保持打开状态约5秒钟。 在Controller2中,我尝试实现类似 但是我不知道在while循环中放入什么来关闭它。我已经尝试了各种方法,但没有任何效果。 问题答案: 使用: