Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/59.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 摇摆同步_Java_Swing - Fatal编程技术网

Java 摇摆同步

Java 摇摆同步,java,swing,Java,Swing,是否有任何方法可以将事件调度线程与另一个由swing.Timer、SwingWorker或new Thread()创建的线程同步?我希望EDT等待另一个线程完成它的工作(例如在屏幕上移动对象),并在完成此工作后立即执行一些任务。可能吗?我必须使用另一个线程,因为如果我试图在EDT中更改对象的坐标,我在屏幕上看不到移动 您不想在EDT上同步或让它加入其他线程,因为这可能会冻结您的程序。您最好的选择可能是使用侦听器类型的结构来通知Swing代码后台线程已完成,例如,可以通过向SwingWorker添

是否有任何方法可以将事件调度线程与另一个由
swing.Timer
SwingWorker
new Thread()
创建的线程同步?我希望EDT等待另一个线程完成它的工作(例如在屏幕上移动对象),并在完成此工作后立即执行一些任务。可能吗?我必须使用另一个线程,因为如果我试图在EDT中更改对象的坐标,我在屏幕上看不到移动

您不想在EDT上同步或让它加入其他线程,因为这可能会冻结您的程序。您最好的选择可能是使用侦听器类型的结构来通知Swing代码后台线程已完成,例如,可以通过向SwingWorker添加
PropertyChangeListener
并侦听“state”属性更改为
SwingWorker.StateValue.done
。如果确实使用此选项,请确保在
PropertyChangeListener
中对
SwingWorker
调用
get()
,以便捕获可能从后台线程中引发的所有异常


编辑
您在评论中声明:

但我会尽力解释的。用户按下按钮。我希望一些JPanel对象由于按下按钮而不断移动到屏幕上的另一个位置。这个动作大约需要0.4秒,我真的不想在这段时间内有任何按钮响应。移动由坐标变换+线程提供。睡眠(5)。似乎不可能在事件分派线程中实现此移动。我说得对吗

  • 是的,如果使用摆动计时器,在EDT上进行移动是完全可能的。Swing计时器在后台使用后台线程,以延迟的方式重复调用其ActionListener的actionPerformed方法。使用它的关键是,在EDT上调用actionPerformed方法中的所有代码
  • 如果要取消激活该按钮,请通过调用
    setEnabled(false)
    将该按钮设置为disabled 1(或更好,它的操作)。动画完成后撤消此操作

  • 例如:

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.RenderingHints;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.image.BufferedImage;
    
    import javax.swing.*;
    
    public class MoveBall extends JPanel {
       private static final int PREF_W = 800;
       private static final int PREF_H = PREF_W;
       private static final int BALL_W = 40;
       private static final int BALL_H = BALL_W;
       private static final Color BALL_COLOR = Color.red;
       public static final int TIMER_DELAY = 20;
       private int ballX = BALL_W / 2;
       private int ballY = BALL_H / 2;
       private BufferedImage ballImg;
       private ButtonAction buttonAction = new ButtonAction("Start Animation");
       private Timer timer;
    
       public MoveBall() {
          ballImg = new BufferedImage(BALL_W, BALL_H, BufferedImage.TYPE_INT_ARGB);
          Graphics2D g2 = ballImg.createGraphics();
          g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
          g2.setColor(BALL_COLOR);
          g2.fillOval(1, 1, BALL_W - 2, BALL_H - 2);
          g2.dispose();
    
          add(new JButton(buttonAction));
       }
    
       @Override
       protected void paintComponent(Graphics g) {
          super.paintComponent(g);
          if (ballImg != null) {
             int x = ballX - BALL_W / 2;
             int y = ballY - BALL_H / 2;
             g.drawImage(ballImg, x, y, null);
          }
       }
    
       @Override
       public Dimension getPreferredSize() {
          if (isPreferredSizeSet()) {
             return super.getPreferredSize();
          }
          return new Dimension(PREF_W, PREF_H);
       }
    
       private class ButtonAction extends AbstractAction {
          public ButtonAction(String name) {
             super(name);
             int mnemonic = (int)name.charAt(0);
             putValue(MNEMONIC_KEY, mnemonic);
          }
    
          @Override
          public void actionPerformed(ActionEvent e) {
             ballX = BALL_W / 2;
             ballY = BALL_H / 2;
             repaint();
             setEnabled(false);
             new Timer(TIMER_DELAY, new TimerListener()).start();
          }
       }
    
       private class TimerListener implements ActionListener {
          @Override
          public void actionPerformed(ActionEvent e) {
             if (ballX + BALL_W / 2 >= getWidth()) {
                stopBall(e);
             } else if (ballY + BALL_H / 2 >= getHeight()) {
                stopBall(e);
             } else {
                ballX++;
                ballY++;
             }
             repaint();
          }
    
          private void stopBall(ActionEvent e) {
             buttonAction.setEnabled(true);
             ((Timer) e.getSource()).stop();
          }
       }
    
       private static void createAndShowGui() {
          MoveBall mainPanel = new MoveBall();
    
          JFrame frame = new JFrame("MoveBall");
          frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
          frame.getContentPane().add(mainPanel);
          frame.pack();
          frame.setLocationByPlatform(true);
          frame.setVisible(true);
       }
    
       public static void main(String[] args) {
          SwingUtilities.invokeLater(new Runnable() {
             public void run() {
                createAndShowGui();
             }
          });
       }
    }
    

    肯定是要走的路。使用
    SwingWorker
    时,在处理结束时会调用
    done()
    方法,这使得在那里调用回调非常容易。@BoristheSpider:是的,但是如果这样做,SwingWorker必须对调用代码有一定的了解,因为它必须调用调用代码的方法来通知它完成,增加耦合。出于这个原因,我通常更喜欢使用PropertyChangeListener.Fair point。使用侦听器确实意味着耦合是单向的。无论哪种方式都比在EDT上同步要好…@Boristeider:是的,100%同意。我的回答没有涉及SwingWorker稳定性的问题,但有些人在使用它时遇到了问题,尤其是指望它正确完成。我还没有看到这个问题,但我也没有把它推到极限。@Alexander:冻结动画或通过更改状态来停止行为是可以的,但你永远都不想冻结Swing事件线程。这会让用户感到非常沮丧。至于你的第二部分,我不知道你在问什么。