Java在Netbeans(Mac)上使用awt、JFrame和Thread(Runnable)绘制一个圆



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类使用basic.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);
//        }

}

洞穴动画很难,好的动画真的很难。你需要对自己重复这一点,因为动画做得好真的很难。

你需要知道的

动画基本上是随着时间变化的幻觉。你很少想执行线性动画,动画通常是在一段时间内完成的,因为它可以平滑平台中的性能差异,这对用户来说并不那么苛刻。

回转是单螺纹的,不是螺纹安全的。这意味着您不应该阻止事件调度线程,并且您必须仅从事件调度线程的上下文中更新UI。

有关的更多详细信息,请参阅Swing中的并发

这让生活有点困难,因为你不能简单地在EDT中运行线性循环,因为这会阻塞UI,而且很难从Thread中完成,因为这是一个混乱的同步。

最简单的解决方案之一是利用可用的API并使用SwingTimer,它充当一个伪循环,在回调之间放入一个小延迟,在这个延迟中您可以执行一些操作

示例

虽然有很多方法可以实现这一点,但我已经设置了一个简单的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);
}
}
}

最新更新