4

我尝试了很多小时。我有一个线程可以更改我的 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,但有些或根本没有发生。

4

4 回答 4

1

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

但是在invokeAndWait() 中存在死锁的可能性,就像在任何创建线程相互依赖的代码中一样。如果调用代码持有一些通过 invokeAndWait() 调用的代码需要的锁(显式或隐式),则 EDT 代码将等待非 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);
}
于 2016-03-21T19:45:56.543 回答
0

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

我认为您实际上并不需要面板,因为 aJLabel可以同时包含图标和文本。请参阅教程

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

于 2014-05-22T05:44:25.587 回答
0

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

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

于 2014-05-14T20:31:10.913 回答
-1

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

于 2013-01-04T22:09:41.650 回答