为什么重复调用repaint()方法不起作用

时间:2018-02-24 07:27:48

标签: java swing

我的目标是在JFrame上放一个按钮和一个圆圈。当我单击按钮时,圆圈应在面板/框架上随机移动

但是当我单击按钮时,圆圈只移动一次,在放入SOP语句后,我发现“ frame.repaint()”被多次调用,但此调用触发了“< em> paintComponent “方法只有一次,这是第一次(在类Panel1中定义)。很奇怪!

我还提供了另一个按预期工作但没有按钮来触发动画的代码。我已经读过 repaint()请求被合并在一起并执行一次,那么第二个程序是如何工作的呢?

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

    public class SimpleGui3c_4 {
        public static void main(String args[]) {
            Frame1 frame = new Frame1();
            frame.go();

        }
    }


    class Frame1 {


        JFrame frame;
        Panel1 p;

            void go() {
        frame = new JFrame();
        JButton button1 = new JButton("Color Change");
        p = new Panel1();

        frame.setSize(500,500);
        frame.setVisible(true);

        frame.getContentPane().add(BorderLayout.SOUTH, button1);
        frame.getContentPane().add(BorderLayout.CENTER, p);
        frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);

        button1.addActionListener(new ColorActionListener());

           }

    class ColorActionListener implements ActionListener {

        public void actionPerformed(ActionEvent e) {


            for(int i=0;i<130;i++) {
                System.out.println("Frame repaint started");
                frame.repaint();
                try {
                Thread.sleep(5000);
            }catch(Exception ex) {} 
            System.out.println("Frame repaint ended");
        }               


    }
}

class Panel1 extends JPanel {
      public void paintComponent(Graphics g) {

    System.out.println("Inside the paint Component method");
    int x = (int)(Math.random()*100);
    int y = (int)(Math.random()*100);
    g.setColor(Color.BLUE);
    g.fillOval(x,y,100,100);
    System.out.println("Exiting the paint component method");

     }
}



}

代码可以工作,但没有按钮来触发动画,它一旦我运行代码就可以工作。我不确定为什么以下程序有效并且上述程序失败了!

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

public class SimpleAnimation {
    int x = 70;
    int y = 70;

    public static void main(String args[]) {
        SimpleAnimation gui = new SimpleAnimation();
        gui.go();
    }

    public void go() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        MyDrawPanel drawPanel = new MyDrawPanel();
        frame.getContentPane().add(drawPanel);
        frame.setSize(300,300);
        frame.setVisible(true);

        for(int i = 0;i<130;i++) {
            //x++;
            //y++;
            drawPanel.repaint();
            try {
                Thread.sleep(50);
            }catch(Exception ex) {}

        }

     }//close go

class MyDrawPanel extends JPanel {
    public void paintComponent(Graphics g) {
        g.setColor(Color.WHITE);
        g.fillRect(0,0,this.getWidth(), this.getHeight());

        int x = (int)(Math.random()*70);
        int y = (int)(Math.random()*70);
        g.setColor(Color.green);
        g.fillOval(x,y,40,40);
    }
}
}

1 个答案:

答案 0 :(得分:1)

  

我还提供了另一个按预期工作但没有按钮来触发动画的代码。

两段代码之间的区别在于它们被调用的上下文。

“工作”的代码实际上已在“主”线程中的偶数调度线程的上下文中更新,这意味着执行Thread.sleep之类的操作不会阻止UI更新

使用事件调度线程的内容(来自ActionListener)更新了无效的代码,这阻止了EDT在actionPerformed之后处理新的绘制请求方法返回

您将面临的另一个问题与您决定更新圈子的位置有关。

可以出于各种不同的原因调用

paintComponent,其中许多是您无法控制的。绘画应该专注于绘制当前状态,不应该直接或间接地修改它。相反,您应该使用某种update方法,它的工作就是更新圆的x / y位置并触发新的绘制周期。

我强烈建议您停下来并花时间阅读:

你的问题是新手的错误,这是由于不了解API的实际工作方式而不是理解可用于解决它的工具

还有许多其他“问题”会导致不良行为,例如最后不调用setVisible,因此不需要再次更新UI以确保添加的组件可见。< / p>

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class SimpleGui3c_4 {

    public static void main(String args[]) {
        new SimpleGui3c_4();
    }

    public SimpleGui3c_4() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                Frame1 frame = new Frame1();
                frame.go();
            }
        });
    }

    public interface Animatable {
        public void update();
    }

    public class Frame1 {

        JFrame frame;
        Panel1 p;

        void go() {
            frame = new JFrame();
            JButton button1 = new JButton("Color Change");
            p = new Panel1();


            frame.getContentPane().add(BorderLayout.SOUTH, button1);
            frame.getContentPane().add(BorderLayout.CENTER, p);
            frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);

            button1.addActionListener(new ColorActionListener(p));

            frame.pack();
            frame.setVisible(true);

        }

        class ColorActionListener implements ActionListener {

            private Animatable parent;

            public ColorActionListener(Animatable parent) {
                this.parent = parent;
            }

            public void actionPerformed(ActionEvent e) {

                JButton btn = (JButton) e.getSource();
                btn.setEnabled(false);

                Timer timer = new Timer(5000, new ActionListener() {
                    private int counter = 0;

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        System.out.println("Frame repaint started");
                        parent.update();
                        counter++;
                        if (counter >= 130) {
                            ((Timer)e.getSource()).stop();
                            btn.setEnabled(true);
                        }
                    }
                });
                timer.setInitialDelay(0);
                timer.start();

            }
        }

        class Panel1 extends JPanel implements Animatable {

            private int xPos, yPos;

            public Panel1() {
                update();
            }

            @Override
            public Dimension getPreferredSize() {
                return new Dimension(200, 200);
            }

            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                System.out.println("Inside the paint component method");
                g.setColor(Color.BLUE);
                g.fillOval(xPos, yPos, 100, 100);
                System.out.println("Exiting the paint component method");

            }

            @Override
            public void update() {
                System.out.println("Inside the update method");
                xPos = (int) (Math.random() * 100);
                yPos = (int) (Math.random() * 100);
                repaint();
            }
        }

    }
}