【问题标题】:javafx call controller function from another threadjavafx 从另一个线程调用控制器函数
【发布时间】:2018-11-02 17:29:34
【问题描述】:

今天的问题是:如何从另一个线程调用控制器函数。我的应用程序如下所示:

public class Server {
//(...)
    public String setMsg(String string) {
       msg.set(string+"\n");
       mainScreenController.updateLog();
    }
//(...)
   while (true){
   doThings();
   }
}

    public class MainScreenController {
//(...)
    public void startServer(){
    new Thread(server::start).start();
    }
     public void updateLog(){
            Platform.runLater(()->{ testAreaLog.setText(testAreaLog.getText() + server.getMsg()); });
        }
//(...)
    }

我想在 finally 块中调用updateLog(),所以每次服务器更新msg GUI 都会将此消息添加到日志窗口。我的msg

private volatile AtomicReference<String> msg = new AtomicReference<String>();

当我在startServer() 中调用updateLog(); 时,它会显示第一条消息Starting server,正如您可能猜到的那样,但调用另一个updateLog(); 会返回null,所以我想在@987654331 之后直接调用它使用@。

【问题讨论】:

  • 我无法理解您在这里要做什么。你想从getMsg()getMsg()updateLog() 调用updateLog() 吗?这不会导致无限递归(假设其中一个在某个时候从您尚未发布的某些代码中调用)?为什么要在finally 块中调用updateLog()?你的Server 不是在单线程上运行吗?为什么msg 需要AtomicReference?制作AtomicReference volatile 绝对没有意义...
  • 抱歉,当然应该在setMsg() 内部。 Server 被称为另一个线程,我想与主 javaFX 线程同步以动态显示新的msgvolatile AtomicReference 是不孕不育的孩子,试图实现同步。
  • 为什么不让updateLog(...)方法有一个字符串参数,直接把string传给它呢?那么您根本不必担心任何同步。 (事实上​​,可能没有理由将“最新消息”存储在 Server 实例中。)
  • 它不能工作,因为我在更新日志时发生了一些事情是另一个线程中的无限循环,所以mainScreenController.updateLog2("LOL"); 只是冻结了服务器
  • 您在问题中发布的任何内容都不会引起任何问题。

标签: multithreading javafx shared-variable


【解决方案1】:

目前还不清楚为什么你不能这样做

public class MainScreenController {
    //(...)

    public void startServer(){
        new Thread(server::start).start();
    }

    public void updateLog(String message){
        Platform.runLater(()-> testAreaLog.appendText(message + "\n"));
    }

    //(...)
}

public class Server {

   public void start() {
       while (true){
           doThings();
           String newMessage = ... ;
           mainScreenController.updateLog(newMessage);
           doMoreThings();
       }
   }

}

这假定您的 while 循环中的某些内容是阻塞(或耗时)调用,因此您不会用过多的 Platform.runLater() 调用淹没 UI 线程。

【讨论】:

  • 好的,那么我应该在哪里初始化MainScreenContoller 来调用这个方法呢?如果您说它不是由我发布的任何内容引起的,我认为现在是问题所在。 ' public void start() { while (true) { MainScreenController mainScreenController = new MainScreenController(); mainScreenController.updateLog2("xD");'当我在这里初始化它时,服务器可以工作,但是updateLog2(string)JavaFX Thread 中抛出NullPointreException,如果我在Server 的开头初始化它,即使它是循环完成的第一件事,它也会冻结。
  • @1337_ 是的,您需要在实际控制器上调用updateLog(...),而不是在您创建的任意对象上调用。在您创建的新实例中,不会初始化任何 UI 字段。 (实际上,它们不会在您在循环的每次迭代中创建的多个新实例中的任何中初始化。)
  • 那是我的问题,我不知道每次Server 中的某些事情发生时如何调用,例如它的聊天服务器日志和连接的人,所以在我的循环中我可以简单地@987654332 @,但是如何在适当的时候将此文本输入到 GUI。
  • @1337_ 你需要向服务器传递一个对实际控制器的引用。您不能只是创建控制器类的新实例,并期望它们以某种方式神奇地了解从 FXML 文件加载的 UI。
  • 好的,所以我应该在创建Server 时传递给服务器的构造Server(MainScreenController mainScreenController);,一切都应该没问题吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-27
  • 1970-01-01
  • 2014-12-11
  • 2014-10-23
相关资源
最近更新 更多