java等待光标显示的问题

我有问题在我的应用程序中显示一个等待光标。 只要鼠标位于定义自己光标的面板上方,等待光标就不会出现。 如果面板不改变光标,等待光标出现。

我附上一个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菜单项不会显示忙光标。

我应该如何解决这个问题?

我强烈希望我的代码不必考虑任何面板,因为要跟踪哪些面板可能处于最前沿是非常困难的。 另外,事件并不总是由于鼠标点击而产生的。

什么是建议的解决方法,以便我可以修改顶级容器的行为?

在搜索互联网之后,我找到了我的问题的答案。

关键是将光标设置在包含要显示忙光标的组件的帧的玻璃窗格上。 我从网上的以下文章中得到了这个想法。

等等,光标,等等!

自动等待游标:WaitCursorEventQueue

我修改了我的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; 

}

 import java.awt.*; import java.awt.event.*; import java.text.SimpleDateFormat; import java.util.Random; import javax.swing.*; import javax.swing.UIManager.LookAndFeelInfo; import javax.swing.table.*; public class TableWithTimer implements ActionListener, Runnable { private static final long serialVersionUID = 1L; private JFrame frame = new JFrame(); private JScrollPane scroll = new JScrollPane(); private JTable myTable; private JPanel buttonPanel = new JPanel(); private JButton startButton = new JButton("Start Thread to Update Table"); private JButton stopButton = new JButton("Stop Thread for Update Table"); private JButton newButton = new JButton("Load new Data to Table"); private int count = 0; private int delay = 3; private javax.swing.Timer timer = null; private boolean runProcess; private int row = 0; private int column = 0; private String value = "Amnd"; private int amndValue = 0; private String valueAt = ""; private SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); private String[] head = {"One", "Two", "Three", "Four", "Five", "Six"}; private String[][] data = new String[25][6]; public TableWithTimer() { myTable = new TableBackroundPaint0(data, head); myTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); myTable.setGridColor(Color.gray); myTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); final TableCellRenderer cellRendener = myTable.getTableHeader().getDefaultRenderer(); myTable.getTableHeader().setDefaultRenderer(new TableCellRenderer() { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { JLabel label = (JLabel) cellRendener.getTableCellRendererComponent( table, value, isSelected, hasFocus, row, column); label.setBackground(Color.orange); label.setForeground(Color.darkGray); label.setFont(new Font("SansSerif", Font.BOLD, 12)); label.setBorder(BorderFactory.createCompoundBorder(label.getBorder(), BorderFactory.createEmptyBorder(0, 5, 0, 0))); label.setHorizontalAlignment(SwingConstants.LEFT); label.setHorizontalAlignment(SwingConstants.CENTER); if ((label.getText().equals("First")) || (label.getText().equals("Second"))) { label.setForeground(Color.red); } if ((label.getText().equals("Day")) || (label.getText().equals("Month")) || (label.getText().equals("Year"))) { label.setForeground(Color.blue); } if ((label.getText().equals("Time"))) { label.setForeground(Color.green); } return label; } }); TableColumnModel cm = myTable.getColumnModel(); for (int column1 = 0; column1 < cm.getColumnCount(); column1++) { TableColumn colLeft1 = cm.getColumn(column1); cm.getColumn(column1).setWidth(140); cm.getColumn(column1).setPreferredWidth(140); } //myTable.setFillsViewportHeight(true); // apply paintComponent for whole Viewport JButton cornerButtonTop = new JButton(); cornerButtonTop.setBackground(scroll.getViewport().getBackground()); JButton cornerButtonBottom = new JButton(); cornerButtonBottom.setOpaque(false); scroll.setCorner(JScrollPane.UPPER_RIGHT_CORNER, cornerButtonTop); scroll.setCorner(JScrollPane.LOWER_RIGHT_CORNER, cornerButtonBottom); scroll.setViewportView(myTable); scroll.setMinimumSize(new Dimension(600, 400)); scroll.setMaximumSize(new Dimension(900, 600)); scroll.setPreferredSize(new Dimension(850, 430)); frame.add(scroll, BorderLayout.CENTER); buttonPanel.setLayout(new GridLayout(1, 4, 10, 10)); startButton.addActionListener(this); startButton.setEnabled(false); stopButton.addActionListener(this); stopButton.setEnabled(false); JButton hideButton = new JButton(); newButton.addActionListener(this); newButton.setEnabled(false); buttonPanel.add(startButton); buttonPanel.add(stopButton); buttonPanel.add(hideButton); buttonPanel.add(newButton); hideButton.setVisible(false); frame.add(buttonPanel, BorderLayout.SOUTH); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLocation(100, 100); frame.pack(); frame.setVisible(true); start(); } @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == startButton) { runProcess = true; new Thread(this).start(); myTable.requestFocus(); startButton.setEnabled(false); stopButton.setEnabled(true); } else if (e.getSource() == stopButton) { scroll.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); runProcess = false; startButton.setEnabled(true); stopButton.setEnabled(false); newButton.setEnabled(true); } else if (e.getSource() == newButton) { runProcess = false; startButton.setEnabled(true); stopButton.setEnabled(false); newButton.setEnabled(false); addNewData(); } } public void addNewData() { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { TableModel model = myTable.getModel(); for (int j = 0; j < model.getRowCount(); j++) { int column = model.getColumnCount(); for (int i = 0; i < column; i++) { model.setValueAt("Deleted", j, i); } } startNewData(); } }); } private void start() { scroll.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); timer = new javax.swing.Timer(delay * 100, updateCol()); timer.start(); } private void startNewData() { scroll.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); count = 0; timer = new javax.swing.Timer(1500, updateCol()); timer.start(); } @Override public void run() { scroll.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); count = 0; Random random = new Random(); while (runProcess) { row = random.nextInt(myTable.getRowCount()); column = random.nextInt(myTable.getColumnCount()); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { try { amndValue++; valueAt = ((myTable.getValueAt(row, column)).toString()); if (!(valueAt.startsWith("A"))) { count++; if (count == ((25 * 6))) { JOptionPane.showMessageDialog(myTable, " Update done "); scroll.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); runProcess = false; } java.util.Date date = new java.util.Date(); String dateTime = sdf.format(date.getTime()); myTable.setValueAt((value + " " + String.valueOf(amndValue) + " at: " + dateTime), row, column); //myTable.setValueAt(new Integer(1), row, column); // please uncoment for generate misstype error on EDT myTable.changeSelection(row, column, false, false); System.out.println("update cycle with value :" + (value + " " + String.valueOf(amndValue) + " at: " + dateTime) + ", table row :" + row + ", table column " + column); } } catch (Exception e) { runProcess = false; System.out.println("Error for update JTable cell"); e.printStackTrace(); } } }); try { Thread.sleep(500); } catch (Exception e) { e.printStackTrace(); } } } public Action updateCol() { return new AbstractAction("text load action") { private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { System.out.println("updating row " + (count + 1)); TableModel model = myTable.getModel(); int cols = model.getColumnCount(); int row = 0; for (int j = 0; j < cols; j++) { row = count; myTable.changeSelection(row, 0, false, false); timer.setDelay(200); Object value = "row " + (count + 1) + " item " + (j + 1); model.setValueAt(value, count, j); } count++; if (count >= myTable.getRowCount()) { myTable.changeSelection(0, 0, false, false); timer.stop(); System.out.println("update cycle completed"); myTable.clearSelection(); startButton.setEnabled(true); newButton.setEnabled(true); scroll.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); } } }; } public static void main(String args[]) { try { for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { System.out.println(info.getName()); if ("Nimbus".equals(info.getName())) { UIManager.setLookAndFeel(info.getClassName()); break; } } } catch (UnsupportedLookAndFeelException e) { // handle exception } catch (ClassNotFoundException e) { // handle exception } catch (InstantiationException e) { // handle exception } catch (IllegalAccessException e) { // handle exception } TableWithTimer tableWithTimer = new TableWithTimer(); } } class TableBackroundPaint0 extends JTable { private static final long serialVersionUID = 1L; TableBackroundPaint0(Object[][] data, Object[] head) { super(data, head); setOpaque(false); ((JComponent) getDefaultRenderer(Object.class)).setOpaque(false); } @Override public void paintComponent(Graphics g) { Color background = new Color(168, 210, 241); Color controlColor = new Color(230, 240, 230); int width = getWidth(); int height = getHeight(); Graphics2D g2 = (Graphics2D) g; Paint oldPaint = g2.getPaint(); g2.setPaint(new GradientPaint(0, 0, background, width, 0, controlColor)); g2.fillRect(0, 0, width, height); g2.setPaint(oldPaint); for (int row : getSelectedRows()) { Rectangle start = getCellRect(row, 0, true); Rectangle end = getCellRect(row, getColumnCount() - 1, true); g2.setPaint(new GradientPaint(start.x, 0, controlColor, (int) ((end.x + end.width - start.x) * 1.25), 0, Color.orange)); g2.fillRect(start.x, start.y, end.x + end.width - start.x, start.height); } super.paintComponent(g); } } 

嗯你的代码有问题在Swing Conconncy有两个领域

替换Thread.sleep(延迟); 和java.swing.Timer中的java.util.Timer,因为块EDT

但在另一方面,有办法如何故意阻止EDT(通过OTN中的splungebob)注意:这个例子是针对所有Swing rulles的,并且仅以这种形式工作,并且作为示例

 import java.awt.*; import java.util.*; import javax.swing.*; import javax.swing.event.*; public class DelayedComboBoxDemo implements Runnable { private JCheckBox chkA = new JCheckBox("A"); private JCheckBox chkB = new JCheckBox("B"); private JCheckBox chkC = new JCheckBox("C"); private JComboBox cboItems = new JComboBox(); private JFrame frame; public static void main(String[] args) { SwingUtilities.invokeLater(new DelayedComboBoxDemo()); } @Override public void run() { cboItems.addItem("-"); JPanel p = new JPanel(); p.add(chkA); p.add(chkB); p.add(chkC); p.add(cboItems); frame = new JFrame("Delayed ComboBox Test"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(p); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); cboItems.addPopupMenuListener(new PopupMenuListener() { @Override public void popupMenuCanceled(PopupMenuEvent e) { } @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { } @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) { int items = cboItems.getItemCount(); rebuildList(); if (items != cboItems.getItemCount()) { cboItems.hidePopup(); cboItems.showPopup(); } } }); } private void rebuildList() { frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); Vector<String> items = new Vector<String>(); if (chkA.isSelected()) { items.add("A"); } else if (chkB.isSelected()) { items.add("B"); } else if (chkC.isSelected()) { items.add("C"); } else { items.add("-"); } cboItems.setModel(new DefaultComboBoxModel(items)); try { Thread.sleep(3000); // simulate a long transaction } catch (InterruptedException ex) { } frame.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); } } 

尝试在框架上设置它,而不是给定的组件

Interesting Posts