https://github.com/terryaa/KOSTA_MAC/tree/master/Java/NetBeans/day13_01_15/src/ex1
我想做的是绘制圆,但是一次在画布上绘制一个圆,然后使用Runnable join继续绘制下一个圆。它应该使用.start()绘制一个圆,而其他.start()不应在正式.start()的绘制圆完成之前开始。
在链接页面的程序包中,Ex3_Canvas1类具有main并使用Runnable MyThread0类使用基本的.start()和.join()绘制圆,它可以完美实现我想要的功能。
我创建了NetBean的自动JFrame类Ex2_CanvasDemo并尝试执行相同的操作,但失败了。绘制一个完整的圆后,将弹出“ JFrame”窗口,然后显示创建下一个圆。我想要的是该窗口应该首先出现,并且它显示了两个圆的创建,而不是同时显示,而是依次显示,例如Ex3_Canvas1。
我猜这是因为主线程等待th(Ex2_CanvasDemo)完成,所以窗口不适用于更改。但是Ex1_Canvas1不应该这样做吗?这种差异是由于netbeans自动生成的代码引起的吗?如何与Ex2_CanvasDemo中的Ex1_Canvas1相同。
我尝试制作一个Runnable类并在Ex2_CanvasDemo中使用,但也失败了。
有帮助吗? 我在Mac上使用的是jdk 8和netbeans8。
-Ex2_CanvasDemo的线程部分-
public Ex2_CanvasDemo() {
initComponents();
Thread th=new Thread(new Runnable() {
@Override
public void run() {
for(int i=0;i<370;i+=10){
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(Ex2_CanvasDemo.class.getName()).log(Level.SEVERE, null, ex);
}
arcNUm=i;
System.out.println("circle"+arcNUm);
canvas1.repaint();
}
}
});
th.start();
try {
th.join();
} catch (InterruptedException ex) {
Logger.getLogger(Ex2_CanvasDemo.class.getName()).log(Level.SEVERE, null, ex);
}
th=new Thread(new Runnable() {
@Override
public void run() {
for(int i=0;i<370;i+=10){
System.out.println("circle"+i);
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(Ex2_CanvasDemo.class.getName()).log(Level.SEVERE, null, ex);
}
arcNum2=i;
canvas2.repaint();
}
}
});
th.start();
// try {
// th.join();
// } catch (InterruptedException ex) {
// Logger.getLogger(Ex2_CanvasDemo.class.getName()).log(Level.SEVERE, null, ex);
// }
}
答案 0 :(得分:0)
动画很难,好的动画真的很难。您需要自己重复一遍,因为正确完成动画非常困难。
动画基本上是随着时间变化的幻觉。您很少要执行线性动画,动画通常需要一段时间才能完成,因为它可以消除平台上的性能差异,这对用户来说并不那么苛刻。
Swing是单线程的,不是线程安全的。这意味着您不应阻塞事件分配线程,而只能在事件分配线程的上下文中更新UI。
有关更多详细信息,请参见Concurrency in Swing
这使生活有些困难,因为您不能简单地在EDT中运行线性循环,因为这会阻塞UI,并且很难通过Thread
进行操作,因为这是一团糟的同步。
最简单的解决方案之一是利用可用的API并使用Swing Timer
,它充当伪循环,使回调之间的延迟很小,您可以在其中执行一些操作>
虽然您可以通过多种方法来解决此问题,但我设置了一个简单的List
,其中包含一堆Animatable
,它们可以“执行任务”,然后在其他串行。
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
TestPane testPane = new TestPane();
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(testPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
testPane.play();
}
});
}
});
}
public class TestPane extends JPanel {
private List<Animatable> animations;
private Animatable animation;
private Timer timer;
public TestPane() {
animations = new ArrayList<>(25);
animations.add(new CircleAnimation(Color.RED));
animations.add(new CircleAnimation(Color.BLUE));
timer = new Timer(5, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (animation == null) {
animation = animations.remove(0);
}
if (animation.update(getBounds())) {
if (animations.isEmpty()) {
((Timer)e.getSource()).stop();
} else {
animation = animations.remove(0);
}
}
repaint();
}
});
}
public void play() {
timer.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (animation != null) {
Graphics2D g2d = (Graphics2D) g.create();
animation.paint(g2d);
g2d.dispose();
}
}
}
public interface Animatable {
public boolean update(Rectangle bounds);
public void paint(Graphics2D g2d);
}
public class CircleAnimation implements Animatable {
private Color color;
private Ellipse2D circle;
private double delta = -1;
public CircleAnimation(Color color) {
this.color = color;
}
@Override
public boolean update(Rectangle bounds) {
if (circle == null) {
circle = new Ellipse2D.Double(bounds.width, (bounds.height / 2) - 10, 20, 20);
}
Rectangle rect = circle.getBounds();
rect.x += delta;
circle.setFrame(rect);
return rect.x + 20 < bounds.x;
}
@Override
public void paint(Graphics2D g2d) {
if (circle == null) {
return;
}
g2d.setColor(color);
g2d.fill(circle);
}
}
}