java等待光标显示问题

时间:2011-05-18 22:24:58

标签: java swing busy-cursor

我在应用程序中显示等待光标时遇到问题。只要鼠标位于定义自己光标的面板上方,就不会出现等待光标。如果面板未更改光标,则会出现等待光标。

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

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

我强烈希望我的代码不必考虑任何面板,因为我很难跟踪哪些面板可能处于最前沿。此外,由于鼠标单击,并不总是生成事件。

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

4 个答案:

答案 0 :(得分:5)

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

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

Wait, Cursor, Wait!

An Automatic Wait Cursor: 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;

}

答案 1 :(得分:4)

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

答案 2 :(得分:2)

嗯,你的代码有问题Concurency in Swing有两个方面

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

但另一方面有办法如何故意阻止EDT(来自OTN的splungebob) 注意:此示例针对所有Swing规则,并且仅以此形式工作并作为示例

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

答案 3 :(得分:1)

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