【问题标题】:Java Swing Thread changing UI - complicationsJava Swing Thread 更改 UI - 并发症
【发布时间】:2012-12-10 02:28:54
【问题描述】:

我尝试了很多小时。我有一个线程可以更改我的 UI 的 JTextField,这完全破坏了 UI。线程(我们称之为线程 A)由 ActionListener 生成。 .setText() 函数调用在线程 A 创建的额外线程 (B) 中。线程 B 是 SwingUtilitis.invokeAll() 和/或 SwingUtilities.invokeAndWait() 的参数。我都试过了。这里有一些代码让它更清楚。

这是我创建线程 A 的 ActionListener - 当然缩短了:

public void actionPerformed(ActionEvent evt) {
    Object source = evt.getSource();
    if (source == window.getBtn_Search()) {
        Refresher refresh = new Refresher();
        refresh.start();
    }
}

这是我的线程 A,稍后将线程 B 放入 EDT 队列:

public class Refresher extends Thread implements Runnable {

private int counter = 0;
private UI window = null;
private int defRefresh = 0;

@Override
public void run() {
    while(true){
        -bazillion lines of code-
                do {
                    try {
                        Refresher.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if(window.canceled()) break;
                    UI.updateCounter(window.getLbl_Status(), (Configuration.getRefreshTime()-counter));
                    counter++;
                } while (counter <= Configuration.getRefreshTime());
             - more code-
    }
}
}

UI.updateCounter(...) 会将线程 B 排队到 EDT。

public static void updateCounter(final JLabel label, final int i) {
    try {
        SwingUtilities.invokeAndWait( 
            new Runnable() {
                public void run() {
                    label.setText("Refreshing in: " + i + " seconds.");
                }
            }
        );
    } catch (InvocationTargetException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

现在,当最后一个函数被调用时,一切都变得一团糟。我尝试了几个小时不同的东西,但没有任何效果。我也尝试过使用 SwingWorker,但有些或根本没有发生。

【问题讨论】:

  • 还有……什么会“搞砸”?
  • 我有一个 JPanel,其中包含多个较小的 JPanel,这些 JPanel 包含一个图标和多个 JLabel。当函数被调用时,这些 JLabel 出现在不同的地方,有些则完全消失。标签 window.getLbl_Status() 与这些无关,完全在其他地方。图标也会改变位置
  • label 值的更改可能会影响其容器及其周围容器的布局
  • 你需要为标签提供足够的空间,当它的文本发生变化时,它不想欺负其余的组件。一种厚颜无耻的方法是使用不可编辑的文本字段。取下它的板子,让它透明。
  • 我想知道使用 JTable 然后更新它的模型而不是一堆 JLabel 是否会更好地为您服务。考虑告诉我们更多关于您的问题的信息。

标签: java multithreading swing user-interface event-dispatch-thread


【解决方案1】:

尝试过的invokeAndWait() 允许发布要在 EDT 上执行的 Runnable 任务,但它会阻塞当前线程并等待 EDT 完成执行任务。

但是在invokeAndWait() 中存在死锁的可能性,就像在任何创建线程相互依赖的代码中一样。 如果调用代码持有一些代码调用的锁(显式或隐式) 通过 invokeAndWait() 要求,则 EDT 代码将等待非 EDT 代码释放锁,这不可能发生,因为非 EDT 代码 正在等待 EDT 代码完成,应用程序将挂起。

正如我们在这里看到的,修改等待非传递的 JLabel 组件 美国东部时间代码。

我们可以使用

invokeLater() 需要 关心创建和排队包含 Runnable 的特殊事件。此事件在 EDT 上按照其接收顺序进行处理,就像任何其他事件一样。 时机成熟时,它通过运行 Runnable 的 run() 方法进行调度。

SwingUtilities.invokeLater(new Runnable() {
public void run() {
label.setText("Refreshing in: " + i + " seconds.");
}
});

或

isEventDispatchThread() 如果调用代码当前正在 EDT 上执行,则返回 true,否则返回 false。

Runnable code= new Runnable() {
                public void run() {
                    label.setText("Refreshing in: " + i + " seconds.");
                }
            }
        );

if (SwingUtilities.isEventDispatchThread()) {
code.run();
} else {
SwingUtilities.invokeLater(code);
}

【讨论】:

    【解决方案2】:

    在更改label 的文本时,您至少应该在label 的最顶层容器上调用repaint()/revalidate(),触发重新布局,假设label 在文本上正确调用invalidate()/revalidate()改变。

    【讨论】:

    • 不,setText() 将触发 revalidate() 和 repaint()。没有必要自己这样做。见grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…
    • 再读一遍,我写的是:“假设标签在文本更改时正确调用 invalidate()/revalidate()”,我从来没有说过这应该由你自己完成
    • 重新验证最顶层的容器没有任何意义,因为标签及其父面板已经通过重新验证并声​​称有效。如果标签文本已经被重新绘制过,即使是在尺寸错误的面板上,重新绘制所有内容会达到什么效果?它只会按原样重新绘制所有内容。您可以建议对标签及其祖父母调用 invalidate,然后对其祖父母进行验证。虽然即使那样我也称它为一种解决方法。
    • 只是想想,你是对的。不知道我当时是怎么想的。
    【解决方案3】:

    我认为您创建的中间 JPanels 可以算作验证根。因此,当您调用setText() 时自动发生的revalidate() 不会导致任何高于JPanel 父级级别的布局更改。

    我认为您实际上不需要面板,因为JLabel 可以同时包含图标和文本。见the tutorial。

    所以我的建议是删除面板,或者,如果它们有目的,请确保面板上的 isValidateRoot() 返回 false。

    【讨论】:

      【解决方案4】:

      通常,标签不太擅长显示变化的文本:它们的宽度变化,以及随之而来的布局。

      使用只读的 JTextField,也许在样式上进行适当的更改,可能是一个更好的解决方案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-11-14
        • 1970-01-01
        • 2013-07-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多