Java中的操作优先级.(对象在GUI更新之前实例化并运行?)

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)

  • Jeanette(kleopatra),其中一位Swing大师说你应该*总是*使用动作而不是ActionListeners,但我不记得她的理由.我使用Actions的动机是你正在改变按钮的标题,而AbstractAction最初会为你做这个(在我的Convert构造函数中的超级调用中).它还允许您在一行代码中创建一个JButton及其行为和标题:`add(new JButton(new Convert("GO","Working ..."))); (2认同)

Pau*_*lin 7

在事件线程中发生"ActionPerformed"回调,通常GUI上的任何内容都不会更新,直到它返回为止.如果你想更新gui,做一些事情,然后再次更新它,你需要更新gui并生成一个线程并返回.然后线程必须执行它的操作,然后执行SwingUtilities.invokeLater来更新gui.


use*_*421 5

试试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)

  • 请注意,这在EDT中运行 - 如果methodName需要很长时间,您的应用程序将冻结.如果您有长时间运行的作业,请使用SwingWorker,并在done()方法中更新标题栏. (6认同)