简体   繁体   English

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

[英]why repeated call to repaint() method did not work

My objective is to put a button and a circle on the JFrame. 我的目标是在JFrame上放置一个按钮和一个圆圈。 When i click the button the circle should move randomly on the panel/frame . 当我单击按钮时,圆圈应在面板/框架上随机移动

But when i click the button the circle just move once only and after putting SOP statements i found that " frame.repaint() " is getting called multiple times but this call is triggering the " paintComponent " method only once, the very first time (defined in class Panel1 ). 但是,当我单击按钮时,圆圈仅移动了一次,并且在放置SOP语句后,我发现“ frame.repaint() ”被调用了多次,但是此调用仅一次触发一次“ paintComponent ”方法(在类Panel1中定义)。 Its very strange! 非常奇怪!

I have also provided another code which works as expected but has no buttons to trigger the animation. 我还提供了另一个代码,该代码可以按预期工作,但没有用于触发动画的按钮。 I have read that repaint() requests are coalesced together and executed once, then how come the second program works? 我读到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");

     }
}



}

Code which works but has no button to trigger the animation, it works as soon as i run the code. 该代码有效,但是没有按钮来触发动画,只要我运行该代码即可。 I am not sure why the below program works and the above program fails! 我不确定为什么下面的程序可以工作,而上面的程序失败!

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

I have also provided another code which works as expected but has no buttons to trigger the animation. 我还提供了另一个代码,该代码可以按预期工作,但没有用于触发动画的按钮。

The difference between the two pieces of code is context within which they are been called. 这两段代码之间的区别在于调用它们的上下文。

The code that "works" is actually been updated out side the context of the Even Dispatching Thread, in the "main" thread, which means that doing something like Thread.sleep won't prevent the UI from been updated. 实际上,“有效”的代码是在“主”线程中的偶发调度线程的上下文之外进行更新的,这意味着执行类似Thread.sleep不会阻止UI的更新。

The code which does not work is been updated from with the content of the Event Dispatching Thread (from within the ActionListener ), which is prevent the EDT from processing new paint requests until after the actionPerformed method returns 不起作用的代码已使用事件分发线程的内容(从ActionListener )进行了更新,这可以防止EDT处理新的绘画请求,直到actionPerformed方法返回为止

Another issue you will face relates to when you decide to update the position of the circle. 当您决定更新圆的位置时,您将面临的另一个问题。

paintComponent can be called for all a number of different reasons, many which you don't control. 可以出于多种不同的原因调用paintComponent ,其中许多原因是您无法控制的。 Painting should focus on painting the current state and should never modify it (directly or indirectly). 绘画应着重于绘画当前状态,而绝不能(直接或间接)对其进行修改。 Instead, you should use some kind of update method, whose job it is, is to update the x/y position of the circle and trigger a new paint cycle. 相反,您应该使用某种update方法,其作用是更新圆的x / y位置并触发新的绘制循环。

I would highly recommend that you stop and take the time to read through: 我强烈建议您停下来并花些时间通读:

Your problem is rookie mistake which comes about from not understanding how the API actually works and not understanding the tools available to solve it 您的问题是菜鸟错误,这是由于不了解API的实际工作原理以及不了解解决该问题的工具而引起的

There are a number of other "issues" which would result in undesirable behaviour, like not calling setVisible last, so the UI doesn't need be updated again to ensure that the components been added are visible. 还有许多其他“问题”会导致不良行为,例如最后一次不调用setVisible ,因此无需再次更新UI以确保添加的组件可见。

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

    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM