3

(在我使用 Swing GUI 的应用程序中)我想在单击 JButton 后调用的循环或方法中执行的某些工作期间显示 GlassPane。

例如:(单击按钮后执行的操作)

if (item.equals(button)) {

    glassPane.setVisible(true);

    someTimeConsumingMethod();

    glassPane.setVisible(false);

}

运行此代码会导致在执行 someTimeConsumingMethod() 期间不显示 glassPane - GUI 会在显示结果之前冻结片刻。删除该循环中的最后一行 (glassPane.setVisible(false);) 会导致在方法完成后显示 glassPane(当 GUI 解冻时)。

有没有一种简单的方法可以在 GUI 冻结之前显示 glassPane,或者我需要在这里使用一些高级知识?(线程?)

更新1:

我已经根据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 数据准备新的 Swing 组件(从 JButtons 和 JLabels 构建的卡片,在需要的地方很少有 JPanel,并将它们添加到正确的位置)。

UPDATE3: 我正在尝试使用 SwingWorker 的 invokeLater 方法使其工作。现在看起来像这样:

(单击按钮后执行的操作)

if (item.equals(button)) {

    glassPane.setVisible(true);

    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() { 
            someTimeConsumingMethod();
            glassPane.setVisible(false);
        }
    });

}

它的效果不如UPDATE1中的代码好(但仍然有效)。问题是:

  • glassPane 加载时没有 .gif 动画(文件在自定义 glassPane 类中设置 - 它适用于UPDATE1代码)

  • “工作”过程结束时有一点延迟 - 第一个光标变为正常(来自 WAIT_CURSOR),并且在很短的时间后 glassPane 消失。光标在激活/停用时由自定义 glassPane 类更改(使用新线程方式无延迟)。

使用 SwingWorker 的 invokeLater 方法是否正确?

编辑:我的错误,我将 SwingWorker 与 SwingUtilities.invokeLater() 混淆了。我猜图像问题是由于 someTimeCONsumingMethod 启动时 GUI 冻结所致。

4

4 回答 4

5

在显示结果之前,GUI 会冻结片刻。删除该循环中的最后一行 (glassPane.setVisible(false);) 会导致在方法完成后显示 glassPane(当 GUI 解冻时)。

这是一个常见的问题Event Dispath Thread,当所有事件都在一瞬间EDT刷新到时,方法中的所有内容都可以在一瞬间完成,Swing GUIif (item.equals(button)) {

但是你的描述说你在 Swing 中遇到了 Concurency 问题,一些代码阻塞 EDT,这是一个小的延迟,例如Thread.sleep(int)可能会导致这个问题,不要这样做,或者将代码块重定向到 Backgroung taks

有没有一种简单的方法可以在 GUI 冻结之前显示 glassPane,或者我需要在这里使用一些高级知识?(线程?)

这个问题是预订示例为什么SwingWorker存在,或者更简单的方法是Runnable#Thread

  • SwingWorker相当保证输出将在 EDT 上实现的方法

  • Swing GUI 的任何输出Runnable#Thread都应包含在invokeLater()

最简单的步骤Jbuttons Action可能是

  • 显示GlassPane

  • 启动后台任务SwingWorker(确保监听PropertyChangeListener)或调用Runnable#Thread

  • 在这一刻ActionListener执行完成其余代码被重定向到Backgroung taks

  • 如果任务结束,则隐藏GlassPane

  • setVisible通过包装来创建简单的 void invokeLater()forRunnable#Thread

  • 在您使用的情况下,您SwingWorker可以隐藏GlassPane正确的事件,PropertyChangeListener或者您可以使用任何(单独的)无效来隐藏GlassPane

@camickr 的 GlassPane 的最佳代码,或者我基于此代码的问题

于 2012-09-26T17:30:21.503 回答
3

您正在使用耗时的工作阻塞 EDT(事件调度线程,处理所有 UI 事件的单个线程)。

2个解决方案:

  1. 将调用包装到: someTimeConsumingMethod();glassPane.setVisible(false);in SwingUtilities.invokeLater(),这将允许框架再次重新绘制自身。但是,这仍然会冻结您的 GUI。

  2. 将您的移动someTimeConsumingMethod()到一个SwingWorker(这是推荐的选项)。这将防止您的 GUI 冻结。

阅读 SwingWorker 的 javadoc 以更好地了解发生了什么以及如何使用它。您还可以在本教程中学到很多关于 Swing 和多线程的知识

于 2012-09-26T17:29:43.610 回答
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();
      }
    });

这里使用的 glasspane 是 FixedGlassPane 玻璃;

参考:http ://www.java2s.com/Code/Java/Swing-JFC/Showhowaglasspanecanbeusedtoblockmouseandkeyevents.htm

于 2012-09-26T16:45:47.763 回答
0

纪尧姆是对的。当您在主线程上时,每一行都将在下一行之前完成。你肯定需要另一个线程。

解决您的问题的一种简单方法是在另一个线程(普通线程或 Swing 线程 - 都可以正常工作)中分离玻璃窗格的显示。

if (item.equals(button)) {
    new Thread(new Runnable(){
        public void run(){
            glassPane.setVisible(true);
        }
    }).start();
    someTimeConsumingMethod();
    glassPane.setVisible(false);
}

这样,在主线程上运行的setvisible(true)while会阻塞不同的线程。someTimeConsumingMethod()完成后,玻璃板将消失。匿名线程到达run方法的末尾并停止。

于 2012-09-26T18:13:22.367 回答