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

时间:2014-01-09 08:14:26

标签: java swing jframe event-dispatch-thread mouse-cursor

另见Java Swing GUI hour glass。但是,提供的答案似乎不起作用。

我有以下代码:

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:moved solution to separate answer

6 个答案:

答案 0 :(得分:5)

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

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

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

答案 1 :(得分:5)

首先制作一个SwingWorker类:​​

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

}

然后这样称呼:

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道歉

  • 我在这里找不到包含此代码的帖子(有关数据库的内容正在发生),

  • 使用此逻辑,

  • 休息在我的评论

  

虚拟-1k错误,错误,错误,你的doInBackground()缺失   publish() - process(),done() is extremly wrong designed,读取@trashgod回答的注释,是否可以使用   Runnable#Thread for FileIO,Socket或任何XxxStreams而不是黑色   基于Future和SwingWorker的漏洞

  • 请按照编辑
  • 在您的主题中删除此代码

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

答案 2 :(得分:3)

  • EventDispatchThread的常见问题是每个事件都在一个瞬间完成,然后在执行ActionListener中的所有代码之后/之后,每一个代码,方法,类都重新绘制

  • 然后你必须将这个逻辑拆分为两个单独的事件包装到(最好的选项)两个Swing Actions,

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

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

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

答案 3 :(得分:2)

加载文件已经使EDT忙,所以它没有机会改变光标。

答案 4 :(得分:2)

哇 - 哇 - 所有的代码。很容易:

final JScrollPane jsp = new JScrollPane(jt);

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

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

答案 5 :(得分:0)

你永远不应该在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);
    }
}