有没有办法将事件调度线程与 swing.Timer
、SwingWorker
或 new Thread()
创建的另一个线程同步?我希望 EDT 等待另一个线程完成它的工作(例如在屏幕上移动对象),并在这项工作完成后立即执行某些任务。是否可以?我必须使用另一个线程,因为如果我尝试在 EDT 中更改对象的坐标,我在屏幕上看不到移动。
最佳答案
您不想在 EDT 上同步或让它加入其他线程,因为这可能会卡住您的程序。也许您最好的选择是使用监听器类型的结构来通知 Swing 代码后台线程已完成,例如可以通过将 PropertyChangeListener
添加到 SwingWorker
来完成此操作code> 并监听“state”属性更改为 SwingWorker.StateValue.DONE
。如果您确实使用此功能,请务必在 PropertyChangeListener
中调用 SwingWorker
上的 get()
,以便捕获可能已发生的所有异常。从后台线程中抛出。
编辑
您在评论中指出:
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?
- 是的,如果您使用 Swing Timer,则很有可能在 EDT 上进行 Action 。 Swing Timer 使用后台线程在幕后延迟重复调用其 ActionListener 的 actionPerformed 方法。其使用的关键是其actionPerformed 方法中的所有代码都在EDT 上调用。
- 如果您想停用该按钮,请通过调用
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/