Swing: Change cursor to wait cursor

妖精的绣舞 提交于 2019-12-21 16:57:46

问题


See also Java Swing GUI hour glass. However the provided answer does not seem to work.

I have following code:

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 is called when user selects the according entry in the menu bar. However the cursor never changes. Note that loading the file takes a file and hence a change in the cursor should be visible.

What am I doing wrong?

EDIT:

this is the top level JFrame.

EDIT 2: moved solution to separate answer


回答1:


The reason why you don't see the changes, is most likely that you are doing all the work on the EDT. Don't ever do that. Even if you // do stuff on a separate thread, the finally block will execute before the UI has had a chance to repaint itself.

Instead, you should spawn a SwingWorker that sets the wait cursor, then does the heavy work (file loading) in the background, and finally resets to the normal cursor when done.

This might show that the wait cursor wasn't really needed in the first place, and that using a progress bar would be more appropriate in this case.




回答2:


First make a SwingWorker class:

private class FileLoader extends SwingWorker<String, Void> {

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

}

Then call it like this:

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

EDIT made by @mKorbel, please apologize me for this hi_jack

  • I can't found my posts with this code here (something happends with underlaing database),

  • use this logics,

  • rest is in my comment here

virtual -1k wrong, wrong, wrong, your doInBackground() missing publish()-process(), done() is extremly wrong designed, read comments in answer by @trashgod, if is possible to use Runnable#Thread for FileIO, Socket or any XxxStreams instead of black hole based on Future and SwingWorker

  • please to delete this code in your thread as per edit

.

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



回答3:


  • common issue for EventDispatchThread is that every events are done in one moment, then every code, methods, classes are repainted in one moments, after/when all code in ActionListener is executed

  • then you have to use split this logics to the two separate events wrapped to the (best of options) two Swing Actions,

    1. one for toggling with Cursor - manage only Cursor can be invoked from PropertyChangeListener or from ButtonModel from JMenuItem

    2. another Swing Action or any SwingListener to call rest of/or expected code

    3. you can to chaining those two Swing Actions (my a.m.), 1st one to call second




回答4:


Loading the file already keeps the EDT busy, so it doesn't get the chance to change the cursor.




回答5:


Wow - whats with all the code. Its easy:

final JScrollPane jsp = new JScrollPane(jt);

jsp.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));

                //DO SOMETHING
jsp.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));



回答6:


You should never run a long process on the Swing Event Dispatch thread (EDT), often however you like to show a wait cursor in the frame while loading some quick data (example when switching panel).

To achieve this I attach the cursor change to the root pane of the JFrame

Example

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


来源:https://stackoverflow.com/questions/21014861/swing-change-cursor-to-wait-cursor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!