java java等待光标显示问题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6051755/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
java wait cursor display problem
提问by Santosh Tiwari
I am having issues displaying a wait cursor in my application. Whenever the mouse is above a panel that defines its own cursor, the wait cursor does not appear. If a panel does not change the cursor, the wait cursor appears.
我在我的应用程序中显示等待光标时遇到问题。每当鼠标位于定义其自身光标的面板上方时,等待光标就不会出现。如果面板未更改光标,则会出现等待光标。
I am attaching a SSCE to accurately explain my problem.
我附上一个 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;
}
Run the attached SSCE.
运行附加的 SSCE。
When the first tab ("Default") is selected, clicking on the 1000ms menu item will show the busy cursor.
选择第一个选项卡(“默认”选项卡(“默认”)时,单击1000ms菜单项将显示忙碌的光标。
When the second tab ("Cursor change") is selected, clicking on the 1000ms menu item does not show the busy cursor.
选择“第二个”选项卡(“光标更改”)时,单击1000ms菜单项未显示忙碌光标。
How should I remedy this problem?
我应该如何解决这个问题?
I would strongly prefer that my code do not have to take into account any of the panels, as it is immensely difficult for me keep track of which panels may be at the forefront. Also, the events are not always generated due to a mouse click.
我强烈希望我的代码不必考虑任何面板,因为我很难跟踪哪些面板可能位于最前沿。此外,事件并不总是由于鼠标点击而生成。
What is the recommended workaround so that I can modify the behavior at the top-level container?
推荐的解决方法是什么,以便我可以修改顶级容器的行为?
采纳答案by Santosh Tiwari
After searching the internet, I found the answer to my question.
在网上搜索后,我找到了我的问题的答案。
The key is to set the cursor on the glasspane of the frame that contains the component which wants to display a busy cursor. I got the idea from the following articles on the net.
关键是将光标设置在包含要显示繁忙光标的组件的框架的玻璃板上。我从网上的以下文章中得到了这个想法。
An Automatic Wait Cursor: WaitCursorEventQueue
I modified my SSCE to make it work for the case when components inside the frame set their own cursor. Here is the modified SSCE.
我修改了我的 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;
}
}
回答by mKorbel
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);
}
}
回答by mKorbel
hmmm you code have problem with Concurency in Swingthere are two areas
replace Thread.sleep(delay); and java.util.Timer with java.swing.Timerbecause block EDT
替换 Thread.sleep(delay); 和 java.util.Timer 与java.swing.Timer因为阻止EDT
but in other hands there is way how to purposely block EDT (by splungebob from OTN) NOTE: this example against all Swing rulles, and works just in this form and as the example
但在其他方面,有一种方法可以故意阻止 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));
}
}
回答by meverett
Try setting it on the frame instead of a given component
尝试将其设置在框架上而不是给定的组件上