Ste*_*ton 6 java user-interface swing multithreading
我希望GUI在实例化对象之前将按钮的标题从"Go"更改为"Working ..."并实际完成工作.完成后,我希望按钮的标题切换回"Go".
这是代码:
private class convert implements ActionListener {
public void actionPerformed(ActionEvent e) {
JButton button = (JButton)e.getSource();
button.setText("Working...");
button.setEnabled(false);
anObject name = new AnObject();
boolean result = name.methodName(chooser.getSelectedFile(),encoding);
// A bunch of stuff was here but irrelevant to the question,
// so it was removed to save room.
button.setEnabled(true);
button.setText("Go");
}
Run Code Online (Sandbox Code Playgroud)
实际发生的做法是名字被实例化,方法名被调用,然后按钮被更新在屏幕上,尽管我已经告诉VM先更改按钮标题.
我的工作理论是,鉴于我没有使这个程序成为线程,这与操作优先级,或JVM的内部线程或某些东西有关...
有什么建议?
Hov*_*els 11
我知道你已经接受了一个解决方案,但是由于你遇到了"冻结gui"综合症,你肯定有一个线程问题,而invokeLater无法解决你的问题.如上所述,你需要一个SwingWorker或一些后台线程来解决这个问题.此外,我认为这是使用AbstractAction而不是ActionListener的好例子.例如:
import java.awt.Dimension;
import java.awt.event.*;
import javax.swing.*;
@SuppressWarnings("serial")
public class Convert extends AbstractAction {
private static final long SLEEP_TIME = 3000; // 3 seconds
private String enabledText;
private String disabledText;
public Convert(String enabledText, String disabledText) {
super(enabledText);
this.enabledText = enabledText;
this.disabledText = disabledText;
}
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (!(source instanceof JButton)) {
return;
}
final JButton button = (JButton) source;
setButtonEnabled(button, false);
new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
// TODO: long-running code goes here.
// Emulated by Thread.sleep(...)
Thread.sleep(SLEEP_TIME);
return null;
}
@Override
protected void done() {
setButtonEnabled(button, true);
}
}.execute();
}
public void setButtonEnabled(JButton button, boolean enabled) {
if (enabled) {
button.setText(enabledText);
button.setEnabled(true);
} else {
button.setText(disabledText);
button.setEnabled(false);
}
}
private static void createAndShowUI() {
JFrame frame = new JFrame("Convert");
frame.getContentPane().add(new ConvertGui());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
@SuppressWarnings("serial")
class ConvertGui extends JPanel {
public ConvertGui() {
add(new JButton(new Convert("GO", "Working...")));
}
@Override
public Dimension getPreferredSize() {
return new Dimension(300, 200);
}
}
Run Code Online (Sandbox Code Playgroud)
在事件线程中发生"ActionPerformed"回调,通常GUI上的任何内容都不会更新,直到它返回为止.如果你想更新gui,做一些事情,然后再次更新它,你需要更新gui并生成一个线程并返回.然后线程必须执行它的操作,然后执行SwingUtilities.invokeLater来更新gui.
试试SwingUtilities.invokeLater().
private class convert implements ActionListener {
public void actionPerformed(ActionEvent e) {
final JButton button = (JButton)e.getSource();
button.setText("Working...");
button.setEnabled(false);
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
anObject name = new AnObject();
boolean result = name.methodName(chooser.getSelectedFile(),encoding);
// A bunch of stuff was here but irrelevant to the question,
// so it was removed to save room.
button.setEnabled(true);
button.setText("Convert");
}
});
}
Run Code Online (Sandbox Code Playgroud)