Swing:将光标更改为等待光标

另请参阅Java Swing GUI沙漏 。 但是,提供的答案似乎不起作用。

我有以下代码:

private void loadFileMenuItemActionPerformed(java.awt.event.ActionEvent evt) { int returnVal = fileChoser.showOpenDialog(this); if (returnVal == JFileChooser.APPROVE_OPTION) { try { this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); // do stuff } finally { this.setCursor(Cursor.getDefaultCursor()); } } } 

当用户在菜单栏中选择相应条目时调用此方法。 但是光标永远不会改变。 请注意,加载文件需要一个文件,因此应该可以看到光标的变化。

我究竟做错了什么?

编辑:

this是顶级JFrame。

编辑2: 将解决方案移至单独的答案

您没有看到更改的原因很可能是您正在完成EDT的所有工作。 不要那样做。 即使你// do stuff在一个单独的线程上执行操作, finally块也会在UI有机会重新绘制之前执行。

相反,您应该生成一个设置等待光标的SwingWorker ,然后在后台执行繁重的工作(文件加载),最后在完成后重置为正常光标。

这可能表明首先不需要等待光标,并且在这种情况下使用进度条会更合适。

首先制作一个SwingWorker类:

 private class FileLoader extends SwingWorker { private final JFrame frame; private final File file; public SdfLoader(JFrame frame, File file) { frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); this.frame = frame; this.file = file; } @Override public String doInBackground() throws IOException { String result = null; // read file and set result; return result; } @Override public void done() { try { String result = get(); //do stuff } catch (ExecutionException | InterruptedException ex) { // display error JOptionPane.showMessageDialog(SdfViewer.this, ioException.getMessage(), "Error opening file", JOptionPane.ERROR_MESSAGE); } finally { frame.setCursor(Cursor.getDefaultCursor()); } } } 

然后这样称呼它:

 private void loadFileMenuItemActionPerformed(java.awt.event.ActionEvent evt) { int returnVal = fileChoser.showOpenDialog(this); if (returnVal == JFileChooser.APPROVE_OPTION) { File file = fileChoser.getSelectedFile(); logger.debug("Opening SD-File '{}'.", file.getAbsoluteFile()); FileLoader loader = new FileLoader(this, file); loader.execute(); } } 

由@mKorbel编辑,请为此hi_jack道歉

  • 我在这里找不到带有此代码的post(与underlaing数据库有关)

  • 使用这个逻辑,

  • rest在我的评论中

虚拟-1k错误,错误,错误,你的doInBackground()缺少publish() – process(), done()是极端错误的设计 ,在@trashgod的回答中读取注释,如果可以使用Runnable #Thread for FileIO,Socket或基于Future和SwingWorker的任何XxxStream而不是黑洞

  • 请按照编辑删除线程中的此代码

 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_INTERVAL_SELECTION); myTable.setRowSelectionAllowed(false); myTable.setColumnSelectionAllowed(true); //myTable.setCellSelectionEnabled(true); 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); } } 
  • EventDispatchThread的常见问题是每个事件都在一个瞬间完成,然后在/当执行ActionListener中的所有代码之后/之后,每个代码,方法,类都重新绘制一次

  • 然后你必须使用拆分这个逻辑到包含两个单独的事件(最好的选项)两个Swing动作,

    1. 一个用于使用Cursor切换 – 仅管理Cursor可以从PropertyChangeListener或从JMenuItem的ButtonModel调用

    2. 另一个Swing Action或任何SwingListener来调用其余的/或预期的代码

    3. 你可以链接那两个Swing Actions(我的),第一个叫第二个

加载文件已使EDT保持忙碌状态,因此无法更改光标。

哇 – 包含所有代码的内容。 这很简单:

 final JScrollPane jsp = new JScrollPane(jt); jsp.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); //DO SOMETHING jsp.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 

你永远不应该在Swing Event Dispatch线程(EDT)上运行一个很长的进程,但是你喜欢在加载一些快速数据时(例如切换面板时)在框架中显示等待光标。

为此,我将光标更改附加到JFrame的根窗格

 public class TestFrame extends JFrame { private static final long serialVersionUID = 5671798241966272024L; /** * In this example static to show how they can be * centralized in application with multiple frames */ public static void setWaitCursor(JFrame frame) { if (frame != null) { RootPaneContainer root = (RootPaneContainer) frame.getRootPane().getTopLevelAncestor(); root.getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); root.getGlassPane().setVisible(true); } } public static void setDefaultCursor(JFrame frame) { if (frame != null) { RootPaneContainer root = (RootPaneContainer) frame.getRootPane().getTopLevelAncestor(); root.getGlassPane().setCursor(Cursor.getDefaultCursor()); } } public TestFrame() { super("Test"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); init(); } private void init() { getContentPane().setLayout(new BorderLayout()); JButton btnTest = new JButton("Load some quick stuff"); btnTest.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { TestFrame.setWaitCursor(TestFrame.this); doSomeShortProccessing(); TestFrame.setDefaultCursor(TestFrame.this); } }); getContentPane().add(btnTest); pack(); } protected void doSomeShortProccessing() { try { //You should never do Thread.sleep on the EDT is just to display function //Normaly process would be create a new panel and load some quick data Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } /** * @param args */ public static void main(String[] args) { TestFrame frame = new TestFrame(); frame.setLocationRelativeTo(null); //Middle of screen frame.setVisible(true); } }