另见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。
答案 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,
用于切换Cursor的一个 - 仅管理Cursor可以从PropertyChangeListener或从JMenuItem的ButtonModel调用
另一个Swing Action或任何SwingListener来调用其余的/或预期的代码
你可以链接那两个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);
}
}