我在应用程序中显示等待光标时遇到问题。只要鼠标位于定义自己的光标的面板上方,就不会出现等待光标。如果面板不更改光标,则会显示等待光标。
我附上SSCE,以准确解释我的问题。
public class BusyCursorTest extends javax.swing.JFrame { public BusyCursorTest() { javax.swing.JMenuBar menuBar = new javax.swing.JMenuBar(); javax.swing.JMenu menu = new javax.swing.JMenu("Menu"); javax.swing.JMenuItem wait1 = new javax.swing.JMenuItem("Wait 100 ms"); javax.swing.JMenuItem wait2 = new javax.swing.JMenuItem("Wait 250 ms"); javax.swing.JMenuItem wait3 = new javax.swing.JMenuItem("Wait 500 ms"); javax.swing.JMenuItem wait4 = new javax.swing.JMenuItem("Wait 1000 ms"); menu.add(wait1); menu.add(wait2); menu.add(wait3); menu.add(wait4); menuBar.add(menu); setJMenuBar(menuBar); wait1.addActionListener(getActionListener(this, delayActionListener(100))); wait2.addActionListener(getActionListener(this, delayActionListener(250))); wait3.addActionListener(getActionListener(this, delayActionListener(500))); wait4.addActionListener(getActionListener(this, delayActionListener(1000))); cursorPanel = new javax.swing.JPanel(); cursorPanel.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseEntered(java.awt.event.MouseEvent e) { cursorPanel.setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.CROSSHAIR_CURSOR)); } public void mouseExited(java.awt.event.MouseEvent e) { cursorPanel.setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.DEFAULT_CURSOR)); } }); javax.swing.JTabbedPane tabbedPane = new javax.swing.JTabbedPane(); tabbedPane.addTab("Default", new javax.swing.JPanel()); tabbedPane.addTab("Cursor change", cursorPanel); getContentPane().add(tabbedPane); setTitle("Cursor test"); setSize(400, 400); setDefaultCloseOperation(javax.swing.JFrame.DISPOSE_ON_CLOSE); setVisible(true); } private java.awt.event.ActionListener delayActionListener(final int delay) { java.awt.event.ActionListener listener = new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent ae) { try { Thread.sleep(delay); } catch (InterruptedException e) { } } }; return listener; } public static void main(String[] args) { new BusyCursorTest(); } public static java.awt.event.ActionListener getActionListener(final java.awt.Component component, final java.awt.event.ActionListener originalActionListener) { java.awt.event.ActionListener actionListener = new java.awt.event.ActionListener() { public void actionPerformed(final java.awt.event.ActionEvent e) { java.util.TimerTask timerTask = new java.util.TimerTask() { public void run() { originalCursor = component.getCursor(); component.setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.WAIT_CURSOR)); } }; java.util.Timer timer = new java.util.Timer(); try { timer.schedule(timerTask, DELAY_MS); originalActionListener.actionPerformed(e); } finally { timer.cancel(); component.setCursor(originalCursor); } } }; return actionListener; } private javax.swing.JPanel cursorPanel = null; public static java.awt.Cursor originalCursor = null; public static final int DELAY_MS = 250; }
运行附带的SSCE。
选择第一个选项卡(“默认”)后,单击1000ms菜单项将显示繁忙的光标。
选择第二个选项卡(“更改光标”)后,单击1000ms菜单项不会显示繁忙光标。
我应该如何解决这个问题?
我强烈希望我的代码不必考虑任何面板,因为对我来说跟踪哪个面板可能是最困难的。此外,由于单击鼠标,并非总是生成事件。
建议的解决方法是什么,以便我可以修改顶级容器的行为?
搜索互联网后,我找到了问题的答案。
关键是将光标设置在包含要显示繁忙光标的组件的框架的玻璃窗格上。我从网上的以下文章中得到了这个主意。
我修改了我的SSCE,使其适用于框架内的组件设置其自己的光标的情况。这是修改后的SSCE。
public class BusyCursorTest extends javax.swing.JFrame { private javax.swing.JPanel cursorPanel = null; public BusyCursorTest() { javax.swing.JMenuBar menuBar = new javax.swing.JMenuBar(); javax.swing.JMenu menu = new javax.swing.JMenu("Menu"); javax.swing.JMenuItem wait1 = new javax.swing.JMenuItem("Wait 100 ms"); javax.swing.JMenuItem wait2 = new javax.swing.JMenuItem("Wait 250 ms"); javax.swing.JMenuItem wait3 = new javax.swing.JMenuItem("Wait 500 ms"); javax.swing.JMenuItem wait4 = new javax.swing.JMenuItem("Wait 1000 ms"); menu.add(wait1); menu.add(wait2); menu.add(wait3); menu.add(wait4); menuBar.add(menu); setJMenuBar(menuBar); wait1.addActionListener(getActionListener(this, delayActionListener(100))); wait2.addActionListener(getActionListener(this, delayActionListener(250))); wait3.addActionListener(getActionListener(this, delayActionListener(500))); wait4.addActionListener(getActionListener(this, delayActionListener(1000))); cursorPanel = new javax.swing.JPanel(); cursorPanel.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseEntered(java.awt.event.MouseEvent e) { cursorPanel.setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.CROSSHAIR_CURSOR)); } public void mouseExited(java.awt.event.MouseEvent e) { cursorPanel.setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.DEFAULT_CURSOR)); } }); javax.swing.JTabbedPane tabbedPane = new javax.swing.JTabbedPane(); tabbedPane.addTab("Default", new javax.swing.JPanel()); tabbedPane.addTab("Cursor change", cursorPanel); getContentPane().add(tabbedPane); setTitle("Cursor test"); setSize(400, 400); setDefaultCloseOperation(javax.swing.JFrame.DISPOSE_ON_CLOSE); setVisible(true); } private java.awt.event.ActionListener delayActionListener(final int delay) { java.awt.event.ActionListener listener = new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent ae) { try { Thread.sleep(delay); } catch (InterruptedException e) { } } }; return listener; } public static void main(String[] args) { new BusyCursorTest(); } public static java.awt.event.ActionListener getActionListener(final javax.swing.JFrame frame, final java.awt.event.ActionListener originalActionListener) { java.awt.event.ActionListener actionListener = new java.awt.event.ActionListener() { public void actionPerformed(final java.awt.event.ActionEvent e) { java.util.TimerTask timerTask = new java.util.TimerTask() { public void run() { originalCursor = frame.getCursor(); startWaitCursor(frame); } }; java.util.Timer timer = new java.util.Timer(); try { timer.schedule(timerTask, DELAY_MS); originalActionListener.actionPerformed(e); } finally { timer.cancel(); stopWaitCursor(frame); } } }; return actionListener; } private static void startWaitCursor(javax.swing.JFrame frame) { frame.getGlassPane().setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.WAIT_CURSOR)); frame.getGlassPane().addMouseListener(mouseAdapter); frame.getGlassPane().setVisible(true); } private static void stopWaitCursor(javax.swing.JFrame frame) { frame.getGlassPane().setCursor(originalCursor); frame.getGlassPane().removeMouseListener(mouseAdapter); frame.getGlassPane().setVisible(false); } private static java.awt.Cursor originalCursor = null; private static final java.awt.event.MouseAdapter mouseAdapter = new java.awt.event.MouseAdapter() { }; public static final int DELAY_MS = 250; }