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)。似乎不可能在事件分派线程中实现此移动。我说得对吗
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事件线程。这会让用户感到非常沮丧。至于你的第二部分,我不知道你在问什么。