代码之家  ›  专栏  ›  技术社区  ›  Domagoj Sabolic

摆动计时器内的油漆不工作

  •  5
  • Domagoj Sabolic  · 技术社区  · 9 年前

    我从未与 Timer 所以我的问题可能真的很愚蠢。我的程序画了一个红色的圆圈,在随机的几秒钟后,圆圈应该变为绿色。我刚做了一个摆动计时器,你可以在下面的代码中看到。它进入了 actionPerformed() 方法,但它不会改变颜色。你能帮我解决我换颜色的问题吗?

    我的代码:

    package igrica;
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Graphics;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.Random;
    
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.Timer;
    
    
    public class ChangingCircle implements ActionListener{
    
    JFrame frame;
    
    Timer timer;
    Random r;
    
    public static void main(String[] args) {
        ChangingCircle gui = new ChangingCircle();
        gui.go();
    }
    
    public void go() {
        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
        MyPanel panel = new MyPanel();
    
        frame.getContentPane().add(BorderLayout.CENTER, panel);
        frame.setSize(300, 300);
        frame.setVisible(true);
    }   
    
    public void actionPerformed(ActionEvent event) {
        frame.repaint();
    }
    
    class MyPanel extends JPanel {
        public void paintComponent(Graphics g) {
    
    
            g.setColor(Color.red);
            g.fillOval(100, 100, 100, 100);
    
            Random r = new Random();
    
            Timer timer = new Timer(r.nextInt(5000) + 1000, new ActionListener() {
                public void actionPerformed(ActionEvent ev) {
                    System.out.println("Timer out");
                    g.setColor(Color.green);
                    g.fillOval(100, 100, 100, 100);
                } 
            });
            timer.start();
        }
    }
    }
    
    3 回复  |  直到 9 年前
        1
  •  8
  •   user1803551    9 年前

    你的代码很混乱。试试这个:

    public class ChangingCircle {
    
        Color color = Color.RED;
        MyPanel panel = new MyPanel();
    
        public static void main(String[] args) {
    
            SwingUtilities.invokeLater(() -> {
                ChangingCircle gui = new ChangingCircle();
                gui.go();
            });
        }
    
        public void go() {
    
            JFrame frame = new JFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            frame.getContentPane().add(panel, BorderLayout.CENTER);
            frame.pack();
            frame.setVisible(true);
    
            Random r = new Random();
            Timer timer = new Timer(r.nextInt(5000) + 1000, new ActionListener() {
    
                public void actionPerformed(ActionEvent ev) {
    
                    System.out.println("Timer");
                    color = Color.GREEN;
                    panel.repaint();
                }
            });
            timer.setRepeats(false);
            timer.start();
        }
    
        class MyPanel extends JPanel {
    
            private int size = 100, loc = 100;
    
            @Override
            public void paintComponent(Graphics g) {
    
                super.paintComponent(g);
                g.setColor(color);
                g.fillOval(loc, loc, size, size);
            }
    
            @Override
            public Dimension getPreferredSize() {
    
                return new Dimension(size + loc, size + loc);
            }
        }
    }
    

    想法是计时器只更改要绘制的形状的属性,然后调用 repaint() 以反映变化。这个 paintComponent 在需要时调用,即使是快速连续调用,也应快速返回。

    具体说明:

    • Start Swing from the EDT .
    • 从外部创建并启动计时器 油漆组件 因为它被多次调用,这将创建和启动许多计时器。
    • 你可能应该把计时器设置为不重复。
    • 呼叫 super.paintComponent(g); 作为里面的第一件事 油漆组件 .
    • 你似乎有一个 ActionListener 那没什么用。

    一般提示:

    • 使用 @Override 注释(如适用)。
    • 呼叫 pack() 而不是手动设置其大小 @覆盖 这个 getPreferredSize 在其上绘制的组件的方法。根据所绘制的内容返回有意义的大小。
    • 使用 add(component, location) 而不是相反(不推荐)。
    • 当局部变量将使用字段时,不要使用字段( Random r 例如)。
    • 使用大写常量名称( Color.RED 而不是 Color.red ).
        2
  •  6
  •   Hovercraft Full Of Eels    9 年前

    不要从paintComponent方法内启动计时器。此方法仅适用于绘画和绘画。相反,在构造函数和Timer的actionPerromed中启动Timer,然后调用 repaint() ,更改类字段的状态,并在paintComponent中使用该信息。使用该字段绘制任何新信息。

    例如

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Graphics;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.Random;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.Timer;
    
    public class ChangingCircle {
        JFrame frame;
    
        public static void main(String[] args) {
            ChangingCircle gui = new ChangingCircle();
            gui.go();
        }
    
        public void go() {
            frame = new JFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            MyPanel panel = new MyPanel();
    
            frame.getContentPane().add(BorderLayout.CENTER, panel);
            frame.setSize(300, 300);
            frame.setVisible(true);
        }   
    
        public void actionPerformed(ActionEvent event) {
            frame.repaint();
        }
    
        class MyPanel extends JPanel {
            private Random r = new Random();
            private boolean draw = false;
    
            public MyPanel() {
                Timer timer = new Timer(r.nextInt(5000) + 1000, new ActionListener() {
                    public void actionPerformed(ActionEvent ev) {
                        draw = true;
                        repaint();
                    } 
                });
                timer.setRepeats(false);
                timer.start();
            }
            public void paintComponent(Graphics g) {
                super.paintComponent(g);
                if (draw) {
                    g.setColor(Color.red);
                    g.fillOval(100, 100, 100, 100);
                }
            }
        }
    }
    

    此外,不要忘记从重写中调用超级的paintComponent方法。

    如果需要更改颜色,请给JPanel一个Color字段,例如调用 color 并在计时器内更改其值,然后调用 重新绘制() 再次在paintComponent中,使用该字段的值绘制椭圆。同样在这种情况下,计时器 应该 重复,所以把它扔掉 timer.setRepeats(false) 在这种情况下。

        3
  •  0
  •   Jiri Tousek    9 年前

    计时器异步工作 paintComponent 在完成计时器的工作之前完成。