【问题标题】:Displaying rotating fan on applet在小程序上显示旋转的风扇
【发布时间】:2013-04-19 02:12:49
【问题描述】:

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

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

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.java 类工作正常(如果我将它作为应用程序运行,将它放在框架中,我可以看到风扇在旋转)。但我就是无法让风扇在 Applet 中旋转。但是,如果我从 Fan.java 类向 Applet 添加类似 JButton 的东西,它就可以工作。

我错过了什么?使用线程和小程序,或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.");
        }
    }

}
}

【问题讨论】:

    标签: java multithreading swing animation paintcomponent


    【解决方案1】:
    while(true) .. repaint(); .. Thread.sleep(10);
    

    这完全是错误的动画制作方式。

    不要阻塞 EDT(事件调度线程)——当这种情况发生时,GUI 将“冻结”。而不是调用 Thread.sleep(n) 实现 Swing Timer 用于重复任务或 SwingWorker 用于长时间运行的任务。有关详细信息,请参阅Concurrency in Swing

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

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

    例如

    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.");
                }
            }
        }
    }
    

    【讨论】:

    • 安德鲁,感谢您的回答。我正在做的编程练习要求我使用线程而不是计时器来制作动画。我担心的是,如果我将它作为应用程序而不是小程序运行,相同的代码可以正常工作。现在,如果它作为应用程序运行良好,那么为什么它也应该作为小程序运行呢? Swing 和线程(以及所有这些东西)之间的复杂性在这两种情况下应该是相同的,对吧?请参阅我的编辑以将其作为应用程序运行。谢谢。
    • 张贴的小程序代码在这里没有编译。一旦“修复”并更改了父级的布局,我就在小程序中看到了旋转的风扇。还修复了 GUI 更新,因此它们在 EDT 上。请务必阅读链接的文章,以便当讲师询问代码为什么会这样做时,您可以解释!
    • 有机会请accept回答。
    猜你喜欢
    • 1970-01-01
    • 2013-12-27
    • 2017-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多