我试了好几个小时。我有一个线程,它改变了我的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()