Java Swing:将光标更改为等待光标
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21014861/
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
Swing: Change cursor to wait cursor
提问by beginner_
See also Java Swing GUI hour glass. However the provided answer does not seem to work.
另请参阅Java Swing GUI 沙漏。但是,提供的答案似乎不起作用。
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.
this
是顶级 JFrame。
EDIT 2: moved solution to separate answer
编辑 2:将解决方案移至单独的答案
采纳答案by beginner_
First make a SwingWorker class:
首先创建一个 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());
}
}
}
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_Hyman
由@mKorbel 编辑,请为这个 hi_Hyman 向我道歉
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
虚拟 -1k 错误,错误,错误,您的 doInBackground() 缺少 publish()-process(),done() 设计非常错误,请阅读@trashgod 的回答中的评论,如果可以将 Runnable#Thread 用于 FileIO、Socket或任何 XxxStreams 而不是基于 Future 和 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);
}
}
回答by Dan D.
Loading the file already keeps the EDT busy, so it doesn't get the chance to change the cursor.
加载文件已经使 EDT 处于忙碌状态,因此它没有机会更改光标。
回答by mKorbel
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,
one for toggling with Cursor - manage only Cursor can be invoked from PropertyChangeListener or from ButtonModel from JMenuItem
another Swing Action or any SwingListener to call rest of/or expected code
you can to chaining those two Swing Actions (my a.m.), 1st one to call second
EventDispatchThread 的常见问题是,每个事件都在一瞬间完成,然后在 ActionListener 中的所有代码执行之后/之后,每个代码、方法、类都在一瞬间重新绘制
那么您必须将此逻辑拆分为包装到(最佳选择)两个 Swing 操作的两个单独事件,
一种用于切换 Cursor - 仅管理 Cursor 可以从 PropertyChangeListener 或从 JMenuItem 的 ButtonModel 调用
另一个 Swing Action 或任何 SwingListener 调用其余/或预期代码
你可以链接这两个 Swing Actions (my am),第一个调用第二个
回答by haraldK
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.
您看不到更改的原因很可能是您正在对 EDT 进行所有工作。永远不要那样做。即使您// do stuff
在单独的线程上,该finally
块也会在 UI 有机会重新绘制自身之前执行。
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.
相反,您应该生成一个SwingWorker
设置等待光标的 ,然后在后台执行繁重的工作(文件加载),最后在完成后重置为普通光标。
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.
这可能表明最初并不真正需要等待光标,在这种情况下使用进度条会更合适。
回答by smac2020
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));
回答by Petter Friberg
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).
你永远不应该在 Swing 事件调度线程 (EDT) 上运行一个很长的进程,但是通常你喜欢在加载一些快速数据时在框架中显示一个等待光标(例如切换面板时)。
To achieve this I attach the cursor change to the root pane of the JFrame
为了实现这一点,我将光标更改附加到 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);
}
}