Java 子阶段侦听器在关闭阶段后不会被杀死

Java 子阶段侦听器在关闭阶段后不会被杀死,java,javafx,parent-child,Java,Javafx,Parent Child,我有一个线程,在我的孩子阶段每5秒运行一次。当我打开和关闭子阶段时,该线程保持运行。点击“关闭”按钮(屏幕右上角的叉号)时,应删除所有孩子的舞台事件和内容。我在儿童舞台内的文本基础上打印文本 它打印为 非空 这意味着节点仍然存在于屏幕上。这将影响应用程序 性能,因为我需要频繁打开和关闭这些子阶段。 请注意,这是我的密码 主类: public class dashboard extends Application { @Override public void start(Stage primar

我有一个线程,在我的孩子阶段每5秒运行一次。当我打开和关闭子阶段时,该线程保持运行。点击“关闭”按钮(屏幕右上角的叉号)时,应删除所有孩子的舞台事件和内容。我在儿童舞台内的文本基础上打印文本

它打印为

非空

这意味着节点仍然存在于屏幕上。这将影响应用程序 性能,因为我需要频繁打开和关闭这些子阶段。 请注意,这是我的密码

主类

public class dashboard extends Application {
@Override
public void start(Stage primaryStage) {

    BorderPane pane = new BorderPane();
    Button btn = new Button("Open child window");
    btn.setOnAction(new EventHandler<ActionEvent>() {
        public void handle(ActionEvent event) {                     
            final Stage dialog = new Stage();
            dialog.setTitle("Sensors Assignment");
            dialog.initModality(Modality.WINDOW_MODAL);
            dialog.initOwner(primaryStage);
            dialog.setResizable(false);

            VBox dialogVbox = (new childWindowClass()).GetChildContent();
            //dialogVbox.getChildren().add(closeButton);

            Scene dialogScene = new Scene(dialogVbox);
            dialog.setScene(dialogScene);
            dialog.showAndWait();

            dialog.setOnCloseRequest(e -> {System.out.println("Stage is closing");dialog.close();});        
        }
    });

    pane.setCenter(new VBox(new Text("Test 1234"), btn));

    ScrollPane scrollPane = new ScrollPane(pane);
    scrollPane.setFitToWidth(true);
    scrollPane.setHbarPolicy(ScrollBarPolicy.NEVER);
    scrollPane.setVbarPolicy(ScrollBarPolicy.AS_NEEDED);        

    Scene scene = new Scene(scrollPane);
    primaryStage.setTitle("test");       
    primaryStage.setMaximized(true);
    primaryStage.setScene(scene);
    primaryStage.show();
}

public static void main(String[] args) {
    launch(args);
}
}

为了在JavaFX中以固定的时间间隔执行与GUI相关的代码,最好使用专用于此的JavaFXAPI。例如,在这里您可以使用
时间线
:参见,例如。当需要停止时,可以轻松调用
Timeline.stop()

杀死一个正在运行的线程有点微妙。在
子窗口类中需要一个布尔标志和一个设置它的方法。然后,您可以通过调用该方法来请求线程停止。您需要注意,在一个线程中对标志所做的更改将被另一个线程看到;在这种情况下,使标志
易失性就足够了。以下方面应起作用:

public class ChildWindowClass {
    private Text txt; 
    private int _index = 0; 
    private SimpleDateFormat dateFrmt = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");

    private volatile boolean stopRequested ;

    public void requestStop() {
        stopRequested = true ;
    }

    public VBox getChildContent() {
        txt = new Text("Child Window Test " + _index);
        Label refreshClock = new Label(dateFrmt.format(new Date()));

        Thread timerThread = new Thread(() -> {  

            // update to stop thread when request is sent

            while (! stopRequested) {
                try { Thread.sleep(5000);  }
                catch (InterruptedException e) {e.printStackTrace();}
                Platform.runLater(() -> {
                    refreshClock.setText(dateFrmt.format(new Date()));
                    try {

                        System.out.println(dateFrmt.format(new Date()) + "  -  " + (txt == null ? "" : " not") + " NULL");
                        if(txt != null)
                            txt.setText("Child Window Test " + _index);
                      _index++;
                    }
                    catch (Exception e) {e.printStackTrace();}                          
                });
            }
        });
        timerThread.start();
        return new VBox(txt, refreshClock);
    }
}
现在您可以执行以下操作。注意,我在这里更改了一些其他代码
showAndWait()
实际上将等待对话框关闭,因此在此之后的代码可以假定对话框已关闭

btn.setOnAction(new EventHandler<ActionEvent>() {
    public void handle(ActionEvent event) {                     
        final Stage dialog = new Stage();
        dialog.setTitle("Sensors Assignment");
        dialog.initModality(Modality.WINDOW_MODAL);
        dialog.initOwner(primaryStage);
        dialog.setResizable(false);

        ChildWindowClass dialogUI = new ChildWindowClass();
        VBox dialogVbox = dialogUI.getChildContent();
        //dialogVbox.getChildren().add(closeButton);

        Scene dialogScene = new Scene(dialogVbox);
        dialog.setScene(dialogScene);
        dialog.setOnCloseRequest(e -> {
            System.out.println("Stage is closing");
            dialog.close();
        });        
        dialog.showAndWait();
        dialogUI.requestStop();
    }
});
btn.setOnAction(新的EventHandler(){
公共无效句柄(ActionEvent事件){
最终阶段对话框=新阶段();
对话框.setTitle(“传感器分配”);
初始化模态(模态窗口模态);
dialog.initOwner(primaryStage);
对话框。可设置大小(false);
ChildWindowClass dialogUI=新的ChildWindowClass();
VBox dialogVbox=dialogUI.getChildContent();
//dialogVbox.getChildren().add(关闭按钮);
场景dialogScene=新场景(dialogVbox);
dialog.setScene(dialogScene);
对话框。setOnCloseRequest(e->{
System.out.println(“阶段结束”);
dialog.close();
});        
dialog.showAndWait();
dialogUI.requestStop();
}
});

这不会中断线程,因此它将继续处于当前睡眠状态,但保证在对话框关闭后五秒钟内退出。如果需要尽快终止它,可以保留对它的引用,并在调用
requestStop()
时调用
Thread.interrupt()
,但这会变得有些复杂。正如我在开始时所说的,最好使用
时间线
,并完全避免使用此类功能的线程。

与您的问题无关:请学习java命名约定并坚持它们。
btn.setOnAction(new EventHandler<ActionEvent>() {
    public void handle(ActionEvent event) {                     
        final Stage dialog = new Stage();
        dialog.setTitle("Sensors Assignment");
        dialog.initModality(Modality.WINDOW_MODAL);
        dialog.initOwner(primaryStage);
        dialog.setResizable(false);

        ChildWindowClass dialogUI = new ChildWindowClass();
        VBox dialogVbox = dialogUI.getChildContent();
        //dialogVbox.getChildren().add(closeButton);

        Scene dialogScene = new Scene(dialogVbox);
        dialog.setScene(dialogScene);
        dialog.setOnCloseRequest(e -> {
            System.out.println("Stage is closing");
            dialog.close();
        });        
        dialog.showAndWait();
        dialogUI.requestStop();
    }
});