在进入循环之前显示GlassPane

时间:2012-09-26 16:18:41

标签: java swing glasspane order-of-execution

(在我使用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冻结。

4 个答案:

答案 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

GlassPane by @camickrquestion about based on this code

的最佳代码

答案 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个解决方案:

  1. 将调用包裹在someTimeConsumingMethod();glassPane.setVisible(false);中的SwingUtilities.invokeLater(),这将允许帧再次重新绘制。但是,这仍然会冻结您的GUI。

  2. someTimeConsumingMethod()移至SwingWorker(这是推荐选项)。这样可以防止GUI冻结。

  3. 阅读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方法的末尾并停止。