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 d
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);
}
}
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.
Wait, Cursor, Wait!
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.
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;
}
hmmm you code have problem with Concurency in Swing there are two areas
replace Thread.sleep(delay); and java.util.Timer with java.swing.Timer because block 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
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));
}
}
Try setting it on the frame instead of a given component