Java 在何处向节点添加事件?

Java 在何处向节点添加事件?,java,javafx,Java,Javafx,您能告诉我,我应该在哪里声明节点的事件侦听器吗?这些节点是在控制器类之外添加的 最好的方法是用这个例子来解释: 我有我的控制器: public class FXMLDocumentController implements Initializable { @FXML private AnchorPane root; @Override public void initialize(URL url, ResourceBundle rb) { Te

您能告诉我,我应该在哪里声明节点的事件侦听器吗?这些节点是在控制器类之外添加的

最好的方法是用这个例子来解释:

我有我的控制器:

public class FXMLDocumentController implements Initializable {

    @FXML
    private AnchorPane root;

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        TestTask test = new TestTask(root);
        Thread th = new Thread(test);
        th.start();
    }    
}
然后我有一个任务,它是在initialize方法中启动的:

public class TestTask extends Task<Void>{

    private AnchorPane root;

    public TestTask(AnchorPane root){
        this.root = root;
    }

    @Override
    protected Void call() throws Exception {
        Button btn = new Button("TestButton");
        Platform.runLater(() -> { root.getChildren().add(btn); });
        return null;
    }
}
公共类TestTask扩展了任务{
隐根;
公共测试任务(锚烷根){
this.root=根;
}
@凌驾
受保护的Void调用()引发异常{
按钮btn=新按钮(“测试按钮”);
Platform.runLater(()->{root.getChildren().add(btn);});
返回null;
}
}

我在这里干什么?我有一个FXML,根元素是锚烷。它具有id根。现在我开始了一个任务,在这个任务中,我向根节点添加了一个按钮。现在我想向按钮注册一个动作事件。我现在的问题是,我可以/应该在哪里注册听众。通常我在控制器中注册它们,但是在这里我不能这样做,因为按钮只存在于任务类中。我可以在Task类中注册它,但我认为它不能很好地扩展到大型应用程序。另一种方法是返回节点,这样我就可以在controller类中访问它,但这里我必须检查它是否已经被添加(为此,我必须调用
task.get()
,它会停止我的应用程序。那么现在您能告诉我:为节点注册侦听器的最佳方法是什么吗?

不要在后台线程中创建UI。有(最多)很少需要这样做。如果需要执行一些长时间运行的任务来检索创建UI所需的数据,请从任务返回数据,然后在任务的
onSucceeded
处理程序中创建UI:

public class SomeControllerClass {

    @FXML
    private AnchorPane root ;

    public void initialize() {
        Task<SomeDataType> task = new MyTask();
        task.setOnSucceeded(e -> {
            // this method executed on FX Application thread.

            SomeDataType result = task.getValue();
            // now create UI and update root, using the data retrieved
        });
        Thread thread = new Thread(task);
        thread.start();
    }

}
公共类SomeControllerClass{
@FXML
隐根;
公共无效初始化(){
Task Task=new MyTask();
task.setonsucceed(e->{
//此方法在FX应用程序线程上执行。
SomeDataType结果=task.getValue();
//现在,使用检索到的数据创建UI并更新根目录
});
线程线程=新线程(任务);
thread.start();
}
}

公共类MyTask扩展了任务{
@凌驾
公共SomeDataType调用(){
SomeDataType结果=longRunningProcess();
返回结果;
}
}

但是为什么不直接在控制器中创建按钮呢?我不明白为什么需要线程?“我必须检查它是否已经添加了”。既然在
call()
方法中创建了一个新按钮,那么它就不可能已经添加了。这只是一个例子。想想类似的事情“为目录中的每个文件创建一个按钮”。您必须动态创建它们,有时在EDT中是不可能的。您在任务中检索数据并返回它,然后在
onSucceeded
处理程序的UI线程上创建按钮。有(几乎?)从来没有理由在后台线程中创建实际的UI组件。也许用一个更现实的例子可以帮助解决你的问题。哦,好吧,我不知道这个…你能给我一个示例代码吗?我只知道如何重写Task类中的onSucceed方法,但我不知道如何在controller类上调用它!你是说类似于if(task.issuceded)-->create按钮??
public class MyTask extends Task<SomeDataType> {

    @Override
    public SomeDataType call() {

        SomeDataType result = longRunningProcess();
        return result ;
    }
}