java - Swing 中的同步

标签 java swing

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

最佳答案

您不想在 EDT 上同步或让它加入其他线程,因为这可能会卡住您的程序。也许您最好的选择是使用监听器类型的结构来通知 Swing 代码后台线程已完成,例如可以通过将 PropertyChangeListener 添加到 SwingWorker 来完成此操作code> 并监听“state”属性更改为 SwingWorker.StateValue.DONE。如果您确实使用此功能,请务必在 PropertyChangeListener 中调用 SwingWorker 上的 get(),以便捕获可能已发生的所有异常。从后台线程中抛出。

For example


编辑
您在评论中指出:

But I'll try to explain. User presses the button. I want some JPanel object to continuously move to another place on screen as a result of button press. This movement will take about 0.4 seconds and I really don't want any button to respond during this time. Movement is provided by coordinates change + Thread.sleep(5). Seems it's impossible to realize this movement in Event Dispatch Thread. Am I right?

  1. 是的,如果您使用 Swing Timer,则很有可能在 EDT 上进行 Action 。 Swing Timer 使用后台线程在幕后延迟重复调用其 ActionListener 的 actionPerformed 方法。其使用的关键是其actionPerformed 方法中的所有代码都在EDT 上调用。
  2. 如果您想停用该按钮,请通过调用 setEnabled(false) 将按钮设置为禁用 1(或者更好,它是 Action)。动画完成后撤消此操作。

例如:

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();
         }
      });
   }
}

关于java - Swing 中的同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28400047/

相关文章:

java - 如何(便宜地)计算n个可能元素的所有可能的length-r组合

java - 如何检查手机上是否启用了 WiFi

java - 注销 Android 时未清除解析数据库

java - 如何使用 Jersey 2.0 发布表单

java swing setBorder速度问题

java - 如何为 GridBagLayout 设置约束

java - 如何使用循环构造来迭代某些 View id?

Java Swing : How to be notified if tool tip is about to become visible?

Java如何制作多个按钮?

java - JXTable日期列