Java在NetBeans(Mac)上使用awt,JFrame和Thread(Runnable)绘制圆

时间:2019-01-16 00:36:21

标签: java multithreading swing jframe

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);
//        }


    }

1 个答案:

答案 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);
        }
    }

}