我有一个像下面这样的方法。
ProgressWindow
是JFrame
的子类,包含JProgressBar
。
addProgress()
会增加JProgressBar
。
如果我从另一个类的方法调用此方法,则ProgressWindow
的框架将显示在框架内但不会显示JProgressBar
和一些JLabels
。它们显示在最后一行(System.out.println("finish")
)之后。
如果我在包含此方法的类中的main方法中调用此方法,则会立即显示每个组件(Bar,labels ...)。
如何才能正确显示窗口?
static void search(){
ProgressWindow window = new ProgressWindow();
window.setVisible(true);
ExecutorService execs = Executors.newFixedThreadPool(Runtime
.getRuntime().availableProcessors());
Collection<Callable<Void>> processes = new LinkedList<>();
for (int i = 0; i < 100; i++) {
processes.add(new Callable<Void>() {
@Override
public Void call() throws Exception {
progressWindow.addProgress(); // increment progress value
return null;
}
});
}
try {
execs.invokeAll(processes);
} catch (Exception e) {
e.printStackTrace();
} finally {
execs.shutdown();
}
System.out.println("finish");
答案 0 :(得分:1)
听起来你想要做的是调用Swing UI线程上的setVisible,你可以使用invokeAndWait或invokeLater执行此操作。
类似于:
final ProgressWindow window = new ProgressWindow();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
window.setVisible(true);
}
});
答案 1 :(得分:1)
主要问题是您似乎是从事件调度线程的上下文中调用search
。
出现问题的原因是您使用execs.invokeAll
阻止所有callables
运行完毕。
这意味着EDT无法处理事件队列中的新事件,包括重新绘制事件,这就是您的用户界面静止不动的原因......
您现在面临许多问题......
我们需要的第一件事是通知搜索已完成的通知,这意味着您在搜索完成时无法再依赖search
返回...
public interface SearchListener {
public void searchCompleted();
}
接下来,我们需要一种中间search
方法来构建用户界面,并确保在其自己的Thread
内启动搜索...
static void search(final SearchListener listener) {
final ProgressWindow window = new ProgressWindow();
window.setVisible(true);
Thread t = new Thread(new Runnable() {
@Override
public void run() {
search(listener, window);
}
});
t.start();
}
然后我们需要修改原始search
方法,以便在搜索完成时使用SearchListener
界面提供通知......
static void search(final SearchListener listener, final ProgressWindow window){
ExecutorService execs = Executors.newFixedThreadPool(Runtime
.getRuntime().availableProcessors());
Collection<Callable<Void>> processes = new LinkedList<>();
for (int i = 0; i < 100; i++) {
processes.add(new Callable<Void>() {
@Override
public Void call() throws Exception {
// This method needs to ensure that
// what ever it does to the UI, it is done from within
// the context of the EDT!!
progressWindow.addProgress();
return null;
}
});
}
try {
execs.invokeAll(processes);
} catch (Exception e) {
e.printStackTrace();
} finally {
execs.shutdown();
}
System.out.println("finish");
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
listener.searchCompleted();
}
});
}
现在,如果没有addProgress
的源代码,我可能会想要使用
processes.add(new Callable<Void>() {
@Override
public Void call() throws Exception {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
progressWindow.addProgress();
}
});
return null;
}
});
}
,而不是...
请查看Concurrency in Swing了解详情