java - 在小程序上显示旋转的风扇

标签 java multithreading swing animation paintcomponent

作为我的编程作业的一部分,我必须在小程序中显示旋转的风扇。

这是我的代码(显示风扇的类):

import javax.swing.*;
import java.awt.*;

public class Fan extends JPanel
{
    private int angle1 = -15;
    private int angle2 = 75;
    private int angle3 = 165;
    private int angle4 = 255;

    public Fan()
    {
        this.setSize(600, 400);
        Runnable spinner = new SpinFan();

        Thread thread1 = new Thread(spinner);
        thread1.start();
    }


    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        g.drawOval(200, 150, 150, 150);
        g.fillArc(210, 160, 130, 130, angle1, 30);
        g.fillArc(210, 160, 130, 130, angle2, 30);
        g.fillArc(210, 160, 130, 130, angle3, 30);
        g.fillArc(210, 160, 130, 130, angle4, 30);
    }
}

class SpinFan implements Runnable
{
    @Override
    public void run() 
    {
        try
        {
            while(true)
            {
                angle1 = (angle1 + 1) % 360;
                angle2 = (angle2 + 1) % 360;
                angle3 = (angle3 + 1) % 360;
                angle4 = (angle4 + 1) % 360;

                System.out.println(angle1 + " " + angle2 + " " + angle3 + " " + angle4);

                repaint();

                Thread.sleep(10);
            }
        }
        catch(InterruptedException ex)
        {
            System.out.println("Problem while putting thread to sleep.");
        }
    }
}

用于进一步处理的类(现在只有 Fan 的实例):

import java.awt.*;
import javax.swing.*;

public class FanControl extends JPanel
{
    public FanControl()
    {
        add(new Fan());
    }
}

最后,这是 Applet 类:

import java.awt.*;
import javax.swing.*;

public class FanApplet extends JApplet
{   
    public FanApplet()
    {
        add(new FanControl());
    }
}

现在我已经尝试了很长一段时间的各种东西,所以请不要介意额外的注释掉的代码。 Fan.jav 类工作正常(如果我将其作为应用程序运行,将其放入框架中,我可以看到风扇旋转)。但我就是无法在小程序中让风扇旋转。但是,如果我将诸如 JButton 之类的东西添加到 Fan.java 类中的 Applet 中,它就会起作用。

我错过了什么?使用线程和小程序或 paintComponent() 和小程序时是否存在一些我似乎不知道的复杂情况。

当我将代码作为应用程序运行时,它工作正常。我可以看到旋转的风扇。这是代码:

import javax.swing.*;
import java.awt.*;

public class Fan extends JPanel
{
private int angle1 = -15;
private int angle2 = 75;
private int angle3 = 165;
private int angle4 = 255;

public Fan()
{
    Runnable spinner = new SpinFan();

    Thread thread1 = new Thread(spinner);
    thread1.start();
}


public static void main(String[] args)
{   
    JFrame frame = new JFrame();
    frame.add(new Fan());
    frame.setSize(600, 400);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
}


@Override
protected void paintComponent(Graphics g)
{
    super.paintComponent(g);

    g.drawOval(200, 150, 150, 150);
    g.fillArc(210, 160, 130, 130, angle1, 30);
    g.fillArc(210, 160, 130, 130, angle2, 30);
    g.fillArc(210, 160, 130, 130, angle3, 30);
    g.fillArc(210, 160, 130, 130, angle4, 30);

}

class SpinFan implements Runnable
{
    @Override
    public void run() 
    {
        try
        {
            while(true)
            {
                angle1 = (angle1 - 1) % 360;
                angle2 = (angle2 - 1) % 360;
                angle3 = (angle3 - 1) % 360;
                angle4 = (angle4 - 1) % 360;

                System.out.println(angle1 + " " + angle2 + " " + angle3 + " " + angle4);

                repaint();

                Thread.sleep(10);
            }
        }

        catch(InterruptedException ex)
        {
            System.out.println("Problem while putting thread to sleep.");
        }
    }

}
}

最佳答案

while(true) .. repaint(); .. Thread.sleep(10);

这完全是错误的动画处理方式。

不要阻塞 EDT(事件调度线程)——发生这种情况时 GUI 将“卡住”。而不是调用 Thread.sleep(n)实现 Swing Timer 用于重复任务或 SwingWorker对于长时间运行的任务。请参阅Concurrency in Swing更多细节。

以下来源使用 Thread在代码中定义,但将 GUI 更新放回 EDT。

但这里真正的问题是动画组件被添加到大小为 0x0 的小程序中。通过将父容器的布局更改为 BorderLayout ,我们可以拉伸(stretch)它以适应可用空间。

EG

import java.awt.*;
import javax.swing.*;

public class FanApplet extends JApplet
{
    private int angle1 = -15;
    private int angle2 = 75;
    private int angle3 = 165;
    private int angle4 = 255;

    public FanApplet()
    {
        add(new FanControl());
    }

    class FanControl extends JPanel
    {
        public FanControl()
        {
            // by setting a BorderLayout and adding a component to the CENTER
            // (default if no constraint specified) the child component will
            // be stretched to fill the available space.
            setLayout(new BorderLayout());
            add(new Fan());
        }
    }

    class Fan extends JPanel
    {
        public Fan()
        {
            //this.setSize(600, 400);
            Runnable spinner = new SpinFan();

            Thread thread1 = new Thread(spinner);
            thread1.start();
        }


        @Override
        protected void paintComponent(Graphics g)
        {
            super.paintComponent(g);

            g.drawOval(200, 150, 150, 150);
            g.fillArc(210, 160, 130, 130, angle1, 30);
            g.fillArc(210, 160, 130, 130, angle2, 30);
            g.fillArc(210, 160, 130, 130, angle3, 30);
            g.fillArc(210, 160, 130, 130, angle4, 30);
        }
    }

    class SpinFan implements Runnable
    {
        @Override
        public void run()
        {
            try
            {
                while(true)
                {
                    angle1 = (angle1 + 1) % 360;
                    angle2 = (angle2 + 1) % 360;
                    angle3 = (angle3 + 1) % 360;
                    angle4 = (angle4 + 1) % 360;

                    System.out.println(angle1 + " " + angle2 + " " + angle3 + " " + angle4);

                    // This ensures that repaint() is called on the EDT.
                    Runnable r = new Runnable() {
                        public void run() {
                            repaint();
                        }
                    };
                    SwingUtilities.invokeLater(r);

                    Thread.sleep(10);
                }
            }
            catch(InterruptedException ex)
            {
                System.out.println("Problem while putting thread to sleep.");
            }
        }
    }
}

关于java - 在小程序上显示旋转的风扇,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16096125/

相关文章:

java - 使用 Java Swing 的管道连接器

java - 从 JPA 2.1 升级到 JPA 2.2

java - || 之间的优先顺序和 && - java

java - 多线程Java

c++ - 带线程的后台函数c++

c++ - 浏览器中的多线程 WebAssembly 比单线程慢,为什么?

java - 在 Java 中显示图像

java - 如何在 hibernate 中使用条件创建内部查询?

java - 奇怪的方法调用优化问题

java - 如何访问JTable中每个单元格的数据