在Linux上使用模式对话框时,Swing呈现繁忙游标的渲染问题

Pra*_*der 4 java linux swing modal-dialog mouse-cursor

在关闭模式对话框后在应用程序框架的玻璃窗格上设置忙碌光标时,不会始终显示忙碌光标.有时它有效(第一次它总是工作),有时不工作.

更好的是,在打开对话框之前设置忙碌光标.显示忙碌光标但是当在内部移动鼠标时,然后在对话框外部时,不再显示忙碌光标.

请注意,我仅在Linux上观察到以下错误.在Mac OS X或Windows上,行为是确定性且一致的.

另一个提示,在代码示例的第一种情况下,当鼠标未进入对话框并且使用键盘选择了YES_OPTION时,始终显示忙碌的鼠标光标.同样在这种情况下,玻璃窗格上的"请稍候......"标签永远不会被绘制.

这里有一个SSCCE演示这些错误:

import java.awt.event.*;
import javax.swing.*;

public class TestFrame extends JFrame {

private JPanel panel;
private JPanel glassPane;

public TestFrame() {
    final JButton button1 = new JButton(new AbstractAction("Start activity indicator after closing the dialog") {
        @Override
        public void actionPerformed(ActionEvent e) {
            doAction1();
        }
    });

    final JButton button2 = new JButton(new AbstractAction("Start activity indicator before opening the dialog") {
        @Override
        public void actionPerformed(ActionEvent e) {
            doAction2();
        }
    });

    panel = new JPanel();
    panel.add(button1);
    panel.add(button2);
    getContentPane().add(panel, BorderLayout.NORTH);

    glassPane = (JPanel) getGlassPane();
    glassPane.setLayout(new BorderLayout());
    glassPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
    glassPane.add(new JLabel("Please Wait..."), BorderLayout.CENTER);

    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setSize(800, 600);
    setVisible(true);
}

public void doAction1() {
    System.out.println("IsStartingInEDT?: "+  SwingUtilities.isEventDispatchThread());
    final int response = JOptionPane.showConfirmDialog(this, "Click on the YES_OPTION, busy indicator must start (if it does, try again).");
    if (JOptionPane.YES_OPTION == response) {
        startActivity();
        for (int i = 0; i < 5; i++) {
            try {
                Thread.sleep(200);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        stopActivity();
    }
}

public void doAction2() {
    startActivity();
    System.out.println("IsStartingInEDT?: "+  SwingUtilities.isEventDispatchThread());
    final int response = JOptionPane.showConfirmDialog(this, "Move the mouse inside the dialog (me) and then outside, the busy indicator is not shown anymore");
    if (JOptionPane.YES_OPTION == response) {
        for (int i = 0; i < 5; i++) {
            try {
                Thread.sleep(200);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    stopActivity();
}

public void startActivity() {
    System.out.println("TestFrame.startActivity()");
    glassPane.setVisible(true);
}

public void stopActivity() {
    System.out.println("TestFrame.stopActivity()");
    glassPane.setVisible(false);
}

/**
 * @param args
 */
public static void main(String[] args) {
    new TestFrame();
}

}
Run Code Online (Sandbox Code Playgroud)

目前我在JavaBug游行中没有发现任何相关问题.我会在开一个新的之前进一步搜索.

我也已经阅读了下面的文章,但它不是很方便,因为从非模态对话中创建一个好的模态对话框并不简单:http: //www.javaspecialists.eu/archive/Issue065.html

有谁可以提供一些帮助?皮埃尔,提前谢谢

J-1*_*DiZ 5

你有一些线程问题.

IsStartingInEDT真的吗?

如果是的话,你做错了,因为:

  • 你不应该在UI线程中睡觉.这将停止屏幕更新.

如果不是,那你做错了因为:

  • OptionPane.showConfirmDialog() 必须从UI线程调用.

你应该做这样的事情:

public void doAction1() {
    if (!SwingUtilities.isEventDispatchThread())  {
         System.err.println("error, must be edt");
         return;
    }

    final int response = JOptionPane.showConfirmDialog(this, "Click on the YES_OPTION, busy indicator must start (if it does, try again).");

    if (JOptionPane.YES_OPTION == response) {
        startActivity();   // change glass panel in edt    

        // new thread for long standing task
        new Thread( new Runnable() { public void run() {    
           for (int i = 0; i < 5; i++) {
               try {
                   Thread.sleep(200);
               } catch (Exception e) {
                   e.printStackTrace();
               }
           }

           SwingUtilities.invokeAndWait(new Runnable(){ public void run() {
              // changing glass panel need edt
              stopActivity();
           });
        }).start();
    }
}
Run Code Online (Sandbox Code Playgroud)