(在我使用Swing GUI的应用程序中)我希望在循环或方法执行的某些工作中显示GlassPane,在单击JButton之后调用它。
例如: (单击按钮后执行的操作)
if (item.equals(button)) {
glassPane.setVisible(true);
someTimeConsumingMethod();
glassPane.setVisible(false);
}
运行此代码导致在执行someTimeConsumingMethod()期间不显示glassPane - 在结果显示之前,GUI只会暂停一会儿。删除该循环中的最后一行(glassPane.setVisible(false);)会导致在方法完成后显示glassPane(当GUI解冻时)。
在GUI冻结之前是否有一种简单的方法来显示glassPane,或者我需要在这里使用一些高级知识? (线程?)
UPDATE1:
我已根据 davidXYZ 答案更新了我的代码(有两处更改):
(单击按钮后执行的操作)
if (item.equals(button)) {
glassPane.setVisible(true);
new Thread(new Runnable(){
public void run(){
someTimeConsumingMethod(); // 1st change: running the someTimeConsumingMethod in new Thread
// instead of setting glassPane to visible
}
}).start();
// 2nd change: moved glassPane.setVisible(false); inside the someTimeConsumingMethod(); (placed at the end of it).
}
第一个改变点是在我的GUI线程中运行someTimeConsumingMethod之前设置glassPane在新线程中可见,在someTimeConsumingMethod完成后显示了glassPane(双重检查了这一点)。
现在它工作正常,谢谢你的所有答案。我一定会检查你提供的所有链接,以便真正了解线程!
UPDATE2: 更多信息:someTimeConsumingMethod();在我的应用程序中,根据XML数据(从JButton和JLabels构建的卡片,在需要的地方使用少量JPanel,并将它们添加到正确的位置)来预装新的Swing组件。
<击>的 UPDATE3: 撞击> 我试图使用SwingWorker的invokeLater方法使其工作。现在它看起来像是:
(单击按钮后执行的操作)
if (item.equals(button)) {
glassPane.setVisible(true);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
someTimeConsumingMethod();
glassPane.setVisible(false);
}
});
}
它的效果不如 UPDATE1 的代码那么好(但仍然 - 它有效)。问题是:
没有.gif动画加载glassPane(文件在自定义glassPane类中设置 - 它适用于 UPDATE1 代码)
“工作”过程结束时有一点延迟 - 第一个光标变为正常(来自WAIT_CURSOR),并且在很短的时间后,glassPane消失。 在激活/取消激活时,自定义glassPane类更改了光标(使用新的Thread方式没有延迟)。
使用SwingWorker的invokeLater方法是否正确?
编辑:我的错误,我将SwingWorker与SwingUtilities.invokeLater()混淆了。我想图像问题是由于当someTimeCOnsumingMethod启动时GUI冻结。
答案 0 :(得分:4)
GUI会在显示结果之前暂停一会儿。删除该循环中的最后一行(glassPane.setVisible(false);)会导致在方法完成后显示glassPane(当GUI解冻时)。
这是关于Event Dispath Thread
的常见问题,当EDT
中的所有事件在一瞬间被刷新到Swing GUI
时,方法if (item.equals(button)) {
中的所有内容都可以在一刻,
但你的描述说你在Swing中遇到了Concurency的问题,有些代码阻塞了EDT,这是一个很小的延迟,例如Thread.sleep(int
)可能导致这个问题,不这样做,或者重定向代码块到了Backgroung taks
在GUI冻结之前是否有一种简单的方法来显示glassPane,或者我需要在这里使用一些高级知识? (线程?)
这个问题是为什么SwingWorker
存在的预订示例,或者更简单的方法Runnable#Thread
SwingWorker
中实现的方法非常保证输出将在EDT上完成
Runnable#Thread
到Swing GUI的任何输出都应包含在invokeLater()
Jbuttons Action
的最简单步骤可能是
显示GlassPane
从SwingWorker
启动后台任务(确保通过PropertyChangeListener
收听)或调用Runnable#Thread
在这一刻ActionListener
执行完成后,其余代码将重定向到Backgroung taks
如果任务结束,则隐藏GlassPane
通过将setVisible
包裹到invokeLater()
Runnable#Thread
如果您使用SwingWorker
,则可以隐藏GlassPane
来自PropertyChangeListener
的正确事件,或者您可以使用任何(单独的)空格来隐藏GlassPane
答案 1 :(得分:2)
JButton startB = new JButton("Start the big operation!");
startB.addActionListener(new ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent A) {
// manually control the 1.2/1.3 bug work-around
glass.setNeedToRedispatch(false);
glass.setVisible(true);
startTimer();
}
});
这里使用的玻璃板是FixedGlassPane玻璃;
参考:http://www.java2s.com/Code/Java/Swing-JFC/Showhowaglasspanecanbeusedtoblockmouseandkeyevents.htm
答案 2 :(得分:2)
您正在使用耗时的工作阻止EDT(事件调度线程,处理所有UI事件的单个线程)。
2个解决方案:
将调用包裹在someTimeConsumingMethod();glassPane.setVisible(false);
中的SwingUtilities.invokeLater()
,这将允许帧再次重新绘制。但是,这仍然会冻结您的GUI。
将someTimeConsumingMethod()
移至SwingWorker
(这是推荐选项)。这样可以防止GUI冻结。
阅读SwingWorker的javadoc,以更好地了解正在发生的事情以及如何使用它。 您也可以在tutorial about Swing and multi-threading
中学到很多东西答案 3 :(得分:0)
Guillaume是对的。当您在主线程上时,每一行将在下一行之前完成。你肯定需要另一个线程。
解决问题的一个简单方法是在另一个线程(正常线程或Swing线程中)旋转玻璃板的显示 - 要么工作正常。
if (item.equals(button)) {
new Thread(new Runnable(){
public void run(){
glassPane.setVisible(true);
}
}).start();
someTimeConsumingMethod();
glassPane.setVisible(false);
}
这样,setvisible(true)
阻止了另一个线程,而主线程上运行someTimeConsumingMethod()
。完成后,玻璃板将消失。匿名线程到达run
方法的末尾并停止。