【问题标题】:Updating swing components correctly正确更新摆动组件
【发布时间】:2012-03-13 08:36:36
【问题描述】:

我一直在设置摆动组件的值,就像我设置任何其他变量一样,但是我遇到了这个页面 - https://bitguru.wordpress.com/2007/03/21/will-the-real-swing-single-threading-rule-please-stand-up/ - 似乎我正在使用事件调度线程对摆动组件进行所有更改 -

那么,这是正确的,我是否应该更改我从这里更新摆动组件的所有代码

    String name = this.getNameTextfield().getText();
    String password = new String(this.getPasswordField().getPassword());
    String confirmPassword = new String(this.getConfirmPasswordField().getPassword());

这个?

java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
               String name = this.getNameTextfield().getText();
               String password = new String(this.getPasswordField().getPassword());
               String confirmPassword = new String(this.getConfirmPasswordField().getPassword());
            }
        });

这是标准做法吗?

编辑:糟糕,刚刚复制并粘贴了我的一些组件相关代码,忽略了它没有更新组件的事实。

【问题讨论】:

  • 请注意我的回答不正确。正确的是 kleopatra 的。

标签: java swing


【解决方案1】:

Swing 圣经有一个chapter on concurrency,底线:

所有与 Swing 组件创建或交互的代码都必须在事件调度线程上运行

(重点是我的)

所以,是的,您始终必须确保您的所有访问(读取或写入)都发生在 EDT 上。

好的一面是:一旦应用程序在 EDT 上正确启动,您就已经上,几乎所有访问都自然发生在 EDT 上。仅当您显式启动另一个线程(f.i. 用于执行冗长的后台任务)并需要向 ui 报告时,情况并非如此:然后您必须将访问调用包装到 invokeLater 中(或使用在内部执行此操作的 SwingWorker)

【讨论】:

  • +1,我不知道,阅读也应该在 EDT 上完成 :-)
  • 你是对的。这个答案应该是公认的。我不能我的,因为它被接受了。但无论如何+1。
【解决方案2】:

字符串是不可变的 - 以下几行几乎是等价的

String password = new String(this.getPasswordField().getPassword());
String password = this.getPasswordField().getPassword();

您没有修改组件。

如果您正在更新它们,那么只有当更新来自另一个线程时。例如,如果您正在从附加到按钮的 ActionListener 更新文本字段,那么这将是不必要的,因为您已经在 Event-Dispatch-Thread 上。

为了获得最大的正确性,您应该首先确定您是否在 EDT。

Runnable update = new Runnable() {
    @Override
    public void run() {
        getNameTextfield().setText("foo");
    }
};
if (SwingUtilities.isEventDispatchThread()) {
    update.run();
} else {
    SwingUtilities.invokeLater(update);
}

【讨论】:

    【解决方案3】:

    在这种特定情况下,您不修改任何组件,因此您不需要在 EDT 上进行,但是当您修改 UI 时,第二种方法是正确的。

    【讨论】:

      【解决方案4】:

      如果您只是从组件中读取数据,那么您可能不需要这样做。大多数从 Swing 组件属性中读取都是线程安全的。

      如果你想在事件调度线程上运行代码,应该使用invokeLater,这通常是你真正想更新GUI的情况。

      有一个short little tutorial here regarding the use of invokeLater

      为了让您的生活更简单并最大程度地降低问题风险,我建议确保与 Swing GUI 交互的任何代码都在 EDT 上运行。正如 kleopatra 正确指出的那样,好消息是这几乎是自动发生的,因为 EDT 将调用所有事件处理代码。

      【讨论】:

      • @kleopatra,也许理论上你是对的,但实际上几乎所有从 Swing 组件属性读取的内容实际上都是线程安全的。毕竟,它们通常只是读取单个字段的简单访问器方法......
      • 是的,它是我们大部分时间都会用线程不安全读取的内容之一 - 主要是因为没有其他线程:-)
      • 比这要好一点,在这种情况下读取实际上 线程安全的 :-) 但我总体上同意你的观点。
      猜你喜欢
      • 2012-12-02
      • 1970-01-01
      • 1970-01-01
      • 2019-02-08
      • 1970-01-01
      • 1970-01-01
      • 2020-09-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多