在Linux上使用modal dialog时,显示繁忙游标的Swing渲染问题

在closures模式对话框后,在应用程序框架的玻璃面板上设置忙碌光标时,并不总是显示忙碌光标。 有时候它是有效的(第一次大多数情况下总能正常工作),有时则不行。

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

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

另一个提示,在代码示例的第一种情况下,当鼠标不进入对话框并且使用键盘selectYES_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(); } } 

目前我在JavaBug游行中没有发现任何相关的问题。 在打开一个新的之前,我会进一步search。

我也已经阅读了下面的文章,但是从一个非modal dialog中做出一个好的模态对话并不是很直接: http : //www.javaspecialists.eu/archive/Issue065.html

任何人都可以提供帮助吗? 先谢了,皮埃尔

这里有一些线程问题。

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(); } } 

1。 通过使用Tread.sleep(int)很好地阻止EDT,所有关于Swing并发性的问题都被描述了出来

2.nd工作,因为JOptionPane的初始化创建一个新的EDT

下面是关于….的简单示范,请仅举例说明,并确保这是针对所有Swing规则,但在EDT期间通过用法Tread.sleep(int)示范性地锁定和解锁EDT

在这里输入图像描述在这里输入图像描述

 import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.*; public class ShakeComponents1 { private JFrame frame = new JFrame(); private final String items[] = {"One", "Two", "Three"}; private Timer timer; private JPanel panel = new JPanel(); private JPanel buttonPanel = new JPanel(); private JButton button = new JButton(" Exit "); private boolean repeats = true; private boolean runs = false; private Color clr[] = {Color.red, Color.blue, Color.magenta}; private Insets initMargin; public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new ShakeComponents1().makeUI(); } }); } public void makeUI() { buttonPanel = new JPanel(); buttonPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); buttonPanel.setLayout(new BorderLayout()); button.setPreferredSize(new Dimension(100, 45)); button.setForeground(Color.darkGray); button.addActionlistner(new Actionlistner() { @Override public void actionPerformed(ActionEvent event) { Runnable doRun = new Runnable() { @Override public void run() { System.exit(0); } }; SwingUtilities.invokeLater(doRun); } }); button.addMouselistner(new java.awt.event.Mouselistner() { @Override public void mouseClicked(MouseEvent e) { } @Override public void mousePressed(MouseEvent e) { } @Override public void mouseReleased(MouseEvent e) { } @Override public void mouseEntered(MouseEvent e) { if (runs) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { runs = false; timer.stop(); changePnlBorder(new EmptyBorder(5, 5, 5, 5)); changeBtnForegroung(Color.darkGray); } }); } } @Override public void mouseExited(MouseEvent e) { if (!runs) { timer.start(); runs = true; } } }); buttonPanel.add(button); final Insets margin = button.getMargin(); panel.add(buttonPanel); for (int i = 0; i < 2; i++) { JComboBox combo = new JComboBox(items); combo.setMinimumSize(new Dimension(50, 25)); combo.setMaximumSize(new Dimension(150, 25)); combo.setPreferredSize(new Dimension(100, 25)); combo.addActionlistner(new ShakeAction()); panel.add(combo); } frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(panel); frame.pack(); frame.setLocation(50, 50); frame.setVisible(true); timer = new Timer(500, new ShakeAction()); timer.setRepeats(repeats); initMargin = button.getMargin(); } private class ShakeAction extends AbstractAction { private static final long serialVersionUID = 1L; private int noColor = 0; private Border border; private int count = 0; @Override public void actionPerformed(ActionEvent e) { timer.start(); if (count > 5) { new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(500); changeBtnForegroung(Color.darkGray); Thread.sleep(500); count = 0; Thread.sleep(750); } catch (Exception e) { System.out.println(e); } } }).start(); } else { new Thread(new Runnable() { @Override public void run() { try { runs = true; if (noColor < 2) { noColor++; changeBtnForegroung(clr[noColor]); } else { noColor = 0; changeBtnForegroung(clr[noColor]); } changeBtnMargin(new Insets(initMargin.top, initMargin.left + 10, initMargin.bottom, initMargin.right - 10)); border = new EmptyBorder(0, 5, 10, 5); changePnlBorder(border); Thread.sleep(100); changeBtnMargin(new Insets(initMargin.top, initMargin.left - 10, initMargin.bottom, initMargin.right + 10)); border = new EmptyBorder(0, 0, 10, 10); changePnlBorder(border); Thread.sleep(100); changeBtnMargin(new Insets(initMargin.top, initMargin.left + 10, initMargin.bottom, initMargin.right - 10)); border = new EmptyBorder(5, 10, 5, 0); changePnlBorder(border); Thread.sleep(100); changeBtnMargin(new Insets(initMargin.top, initMargin.left - 10, initMargin.bottom, initMargin.right + 10)); border = new EmptyBorder(10, 10, 0, 0); changePnlBorder(border); Thread.sleep(100); changeBtnMargin(new Insets(initMargin.top, initMargin.left, initMargin.bottom, initMargin.right)); border = new EmptyBorder(5, 5, 5, 5); changePnlBorder(border); Thread.sleep(100); count++; } catch (Exception e) { System.out.println(e); } } }).start(); } } } private void changePnlBorder(final Border b) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { buttonPanel.setBorder(b); buttonPanel.revalidate(); buttonPanel.repaint(); } }); } private void changeBtnForegroung(final Color c) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { button.setForeground(c); } }); } private void changeBtnMargin(final Insets margin) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { button.setMargin(margin); } }); } } 

结论 – >你可以创建新的Thread作为Backgroung任务包装成Runnable ,如果你想模拟LongRunning任务和Thread.sleep(int),也许回答你的问题在这里

确定正确的方法是使用SwingWorker ,Thread.sleep(int)也是如此