答案歸結爲它是什麼你想達到...
進口的是記住,Swing是單線程環境,也就是說,它希望所有的相互作用,變更,修改,從事件調度線程的上下文中完成對UI的更新和創建。
阻止EDT的任何操作(例如sleep
,wait
等)將阻止EDT重新繪製UI或響應新事件。實現這一
的一種方式是通過使用javax.swing.Timer
這是使用3個定時器鏈接在一起非常簡單的例子。就個人而言,我會用配置很短的時間刻度,並檢查是否出現所需的延遲時間,然後相應地更改狀態,一個計時器,但這種跨獲取點......
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class SimpleTimer {
public static void main(String[] args) {
new SimpleTimer();
}
public SimpleTimer() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Timer red;
private Timer green;
private Timer yellow;
private Color color = Color.GREEN;
private Point spot;
public TestPane() {
red = new Timer(500, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
color = Color.RED;
green.start();
repaint();
}
});
green = new Timer(2000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
color = Color.GREEN;
yellow.start();
repaint();
}
});
yellow = new Timer(1000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
color = Color.YELLOW;
red.start();
repaint();
}
});
red.setRepeats(false);
green.setRepeats(false);
yellow.setRepeats(false);
green.start();
addMouseMotionListener(new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
spot = e.getPoint();
repaint();
}
});
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int radius = 20;
int x = (getWidth() - radius)/2;
int y = (getHeight() - radius)/2;
g2d.setColor(color);
g2d.fillOval(x, y, radius, radius);
if (spot != null) {
x = spot.x - 5;
y = spot.y - 5;
g2d.setColor(Color.RED);
g2d.drawOval(x, y, 10, 10);
g2d.setColor(Color.YELLOW);
g2d.fillOval(x, y, 10, 10);
}
g2d.dispose();
}
}
}
另一種選擇是使用SwingWorker
,這允許在後臺線程中執行某種處理(使EDT運行),但提供了可以簡單地將結果同步回EDT的方法。
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class SimpleTimer {
public static void main(String[] args) {
new SimpleTimer();
}
public SimpleTimer() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Color color = Color.GREEN;
private Point spot;
public TestPane() {
new Switcher().execute();
addMouseMotionListener(new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
spot = e.getPoint();
repaint();
}
});
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int radius = 20;
int x = (getWidth() - radius)/2;
int y = (getHeight() - radius)/2;
g2d.setColor(color);
g2d.fillOval(x, y, radius, radius);
if (spot != null) {
x = spot.x - 5;
y = spot.y - 5;
g2d.setColor(Color.RED);
g2d.drawOval(x, y, 10, 10);
g2d.setColor(Color.YELLOW);
g2d.fillOval(x, y, 10, 10);
}
g2d.dispose();
}
public class Switcher extends SwingWorker<Void, Color> {
@Override
protected void process(List<Color> chunks) {
color = chunks.get(chunks.size() - 1);
repaint();
}
@Override
protected Void doInBackground() throws Exception {
while (true) {
publish(Color.GREEN);
Thread.sleep(2000);
publish(Color.YELLOW);
Thread.sleep(500);
publish(Color.RED);
Thread.sleep(2000);
}
}
}
}
}
退房Concurrency in Swing更多細節
那是......不是定時器做。 –
好的,謝謝。如果你知道怎麼做,那麼你能回答我如何在循環中發生3個連續任務,並且時間在他們之間? – Yesha
你不希望程序等待。我們的想法是,每一個計時器滴答它會改變程序的狀態時某種方式,然後畫和下一個計時器開始... – MadProgrammer