Java Swing线程改变UI -复杂性



我试了好几个小时。我有一个线程,它改变了我的UI的JTextField,这完全破坏了UI。线程(我们叫它线程A)是由一个ActionListener生成的。. settext()函数调用在线程a创建的额外线程(B)中。线程B是SwingUtilitis.invokeAll()和/或swingutilitis . invokeandwait()的参数。我两种都试过了。这里有一些代码使它更清楚。

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

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,但是有些或者什么都没发生。

invokeAndWait()尝试允许在EDT上发布一个可运行的任务,但它阻塞当前线程并等待,直到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);
}

一般来说,标签不太擅长显示改变了的文本:它们的宽度改变了,布局也随之改变了。

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

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

我不认为你实际上需要面板,因为一个JLabel可以包含一个图标和文本。

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

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

相关内容

  • 没有找到相关文章

最新更新