【问题标题】:How to update JFrame Label within a Thread? - Java如何在线程中更新 JFrame 标签? - 爪哇
【发布时间】:2011-05-14 02:51:18
【问题描述】:

我尝试了很多,但似乎无法让它发挥作用。

有人告诉我在以下示例中使用 EDT。

    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            //  Modify the GUI here
        }
});

我已经阅读了很多关于这个主题的内容,但仍然不明白。我知道线程是什么,但 .invokeLater 对我来说仍然没有意义。老实说,如果你能详细解释这将是一个很大的帮助!

程序目标:获取每秒不断创建的随机生成的密钥,以便之后在 GUI 中自行更新。

【问题讨论】:

  • 除了下面@John V. 的回答,您可能还想阅读这篇文章:Threads and Swing

标签: java user-interface jframe


【解决方案1】:

所以有一个 EDT(事件调度线程)。出现在屏幕上的所有操作都由 EDT 执行。每个 Swing 应用程序只有一个 EDT。

您在某个任意线程中,并且想通过该线程更新 GUI?就像我说的每个摇摆应用程序只有一个 EDT,所以你必须告诉 EDT 显示标签(或任何你想要的上下文)。

这里的想法是将这个 Runnable 推送到 EDT 从中提取的队列中。最终,当所有其他操作完成时,EDT 将处理您的可运行文件。

【讨论】:

    【解决方案2】:

    我建议你买本书Filthy Rich Clients。有一章非常详细地解释了 Swing 的线程模型。

    基本上在 Swing 中,任何修改 GUI 的代码都应该在 Event Dispatcher 线程中执行。您在那里使用的SwingUtilities 类为您提供了一种将事件发布到事件队列的简单方法,该事件队列随后由 EDT 分派。这就是 invokeLater 方法的作用,它以 new Runnable() 作为参数,最终在 EDT 上执行。

    从书中:

    invokeLater() 实现需要 关心创建和排队一个特殊的 包含 Runnable 的事件。这 事件在 EDT 中处理 订单收到了,就像任何 其他事件。时机一到,它 通过运行调度 Runnable 的 run() 方法。

    【讨论】:

    • 今晚我要去买那本书,谢谢你的建议
    【解决方案3】:

    这是所有 GUI 编程中非常常见的元素。您有一个线程来处理绘制 GUI、获取输入和运行回调。如果另一个线程试图更改 GUI 相关对象,它将与 GUI 线程发生冲突。比如说,画了一半,你从不同的线程改变颜色。

    invokeLater 所做的只是排队等待 GUI 线程运行。通过“稍后”,它实际上几乎立即运行,但当前线程不必等待它。 GUI 线程可能正在绘制或等待回调返回,这会延迟执行您提供的代码。

    【讨论】:

      【解决方案4】:

      需要成为成员,以便我们可以更改它并仍然从内部类中使用它

      protected long secret=0;
      

      ...这需要在您的代码中运行...

      JFrame f = new JFrame("foo");
      new Thread(){
              public void run() {
                  for(;;){
                      try { 
                          sleep(1000);
                      } catch Interrupted (Exception ix){ 
                          return;
                      }
                      // TODO update your secret key here
                      // please don't use random()
      
                      SwingUtilities.invokeLater(new Runnable() {
                          public void run() {
                              f.setTitle("secret "+x);
                          }
                      });
                  }
              }
         }).start();
      

      ....

      只有从 EDT 更新 Swing 才能正确绘制。

      当您在 EDT 中(在事件处理程序中运行代码)时,如果您确实需要,可以调用 paintImmediately()。

      【讨论】:

        【解决方案5】:

        如果您只想按照已知的时间表更新 UI,请尝试以下操作。这假定 JFrame 是您希望每 1 秒更新一次的组件。

        private static final int WAIT_LENGTH = 1000; // 1 second
        private JFrame frame = new JFrame();
        
        // Thread will update the UI (via updateUI() call) about every 1 second
        class UIUpdater extends Thread {
          @Override
          void run() {
            while (true) {
              try {
                // Update variables here
              }
              catch (Exception e) {
                System.out.println("Error: " + e);
              }
              finally {
                frame.repaint();
                Thread.sleep(WAIT_LENGTH);
              }
            }
          }
        }
        

        要开始这个话题:

        UIUpdater t = new UIUpdater();
        t.start();
        

        【讨论】:

        • .updateUI();不断出现错误,每当我尝试使用 .setText(); 更改标签时您在这里发布//更新变量的地方我总是以它没有帮助我而告终。所以我认为我需要 mainFrame 而不是 JFrame(它扩展了我之前使用的 JFrame),所以这不起作用......所以基本上我看不到这甚至可以让我更新它。我肯定会阅读建议的“肮脏的富客户”这本书......
        • 事实证明component.repaint() 更符合您的要求。对不起。我已经更新了我的答案。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-09-02
        • 2013-10-13
        • 2016-02-16
        • 1970-01-01
        • 1970-01-01
        • 2013-03-19
        • 1970-01-01
        相关资源
        最近更新 更多