JPanel没有在第二次鼠标点击时更新

时间:2013-11-13 15:39:29

标签: java swing jframe

完成并运行一个简单的程序后,可以在单击时更改形状的颜色:

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

class MyPanel extends JPanel{
    int x = 200,y = 200,r = 50;
    static Color co = Color.BLUE;
    static final JFrame frame = new JFrame();
    public static void main(String[] args){
        frame.setTitle("Color Change with Mouse Click");
        frame.setSize(500,500);
        MyPanel pane = new MyPanel();
        frame.add(pane);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pane.setVisible(true);
        }

    public void Panel(){
        addMouseListener(new MouseAdapter(){
            public void mouseClicked(MouseEvent e){
                if(((e.getX() >= (x-r) && e.getX() < (x+r) && e.getY() >= (y-r) && e.getY() < (y+r))) & (co == Color.GREEN)){
                    co = Color.BLUE;
                    repaint();
                };
                if(((e.getX() >= (x-r) && e.getX() < (x+r) && e.getY() >= (y-r) && e.getY() < (y+r))) & (co == Color.BLUE)){
                    co = Color.GREEN;
                    repaint();
                };
            }
        });
    }

    Timer timer = new Timer(1, new ActionListener(){
        @Override
        public void actionPerformed(ActionEvent e){
            Panel();
        }
    });

    @Override
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        timer.start();
        Panel();
        g.setColor(co);
        g.fillOval(x-r, y-r, 2*r, 2*r);
        repaint();
    }
}

我遇到了一个我根本不知道如何修复的问题。 JPanel永远不会在第二次鼠标点击时更新,仅在第一次点击时更新。我认为添加计时器可以解决这个问题,但显然它没有。非常感谢帮助。

编辑: 我根据Aqua的建议改变了我的代码:

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

class MyPanel extends JPanel{
    int x = 200,y = 200,r = 50;
    static Color co = Color.BLUE;

    public static void main(String[] args){
        final JFrame frame = new JFrame();
        frame.setTitle("Color Change with Mouse Click");
        MyPanel pane = new MyPanel();
        frame.add(pane);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        }

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

    public void panel(){
        addMouseListener(new MouseAdapter(){
            public void mouseClicked(MouseEvent e){
                if(((e.getX() >= (x-r) && e.getX() < (x+r) && e.getY() >= (y-r) && e.getY() < (y+r))) && (co == Color.GREEN)){
                    co = Color.BLUE;
                    repaint();
                }else if(((e.getX() >= (x-r) && e.getX() < (x+r) && e.getY() >= (y-r) && e.getY() < (y+r))) && (co == Color.BLUE)){
                    co = Color.GREEN;
                    repaint();
                }else{
                    repaint();
                };
            }
        });
    }
    public MyPanel(){
        Timer timer = new Timer(20, new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e){
                panel();
            }
        });
        timer.start();
    }
    @Override
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        g.setColor(co);
        g.fillOval(x-r, y-r, 2*r, 2*r);
        repaint();
    }
}

现在颜色变化有效,但颜色变化有点不可预测。有时它有延迟,有时它没有,有时它完全不会改变。这是我的计时器的问题吗?

2 个答案:

答案 0 :(得分:2)

Panel()调用paintComponent()会触发无限循环,导致StackOverflowError异常。由于repaint()最终会调用paintComponent()

您应该在面板初始化时附加一次鼠标侦听器,而不是每次重新绘制。计时器也一样。但是,目前还不清楚这个样本中计时器的用意是什么。

发布代码的其他一些问题:

  1. 致电frame.setVisible(true);而不是pane.setVisible(true);发布时代码不起作用。也无需在面板中保留静态成员JFrame frame。您只需在JFrame中声明并使用main()即可。

  2. paintComponent()仅用于绘画。避免使用该方法中的复杂逻辑。不要设置定时器或调用其他初始化方法。执行paintComponent时几乎无法控制,并且必须快速才能获得最佳绘图效果。浏览Performing Custom Painting教程。将计时器和鼠标监听器的初始化移出到面板的构造函数。

  3. 请勿使用frame.setSize(500,500);,而是覆盖JPanel.getPreferredSize()。有关详细信息,请参阅Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?

  4. 坚持Java命名约定。名为Panel()的方法令人困惑。见Naming Conventions

  5. else方法中缺少Panel()语句。在第二次单击时,首先进入第一个if语句,将颜色设置为蓝色,然后输入第二个if语句并将颜色重置为绿色。

  6. 如上文评论中所述,&&&是不同的运营商。见Operators

答案 1 :(得分:2)

计时器有什么意义?计时器用于安排事件。您没有安排任何事件,您正在等待用户单击鼠标。不需要定时器。如果您确实需要定时器,那么:

  1. 你永远不会安排计时器每毫秒启动一次,这对机器来说太快了。根据要求使用更实际的值。可能是50或100毫秒。

  2. 你永远不会在绘画方法中启动Timer。你可能会在你的类的构造函数中启动Timer。

  3. 您的MouseListener代码错误。启动Timer并调用调用addMouseListener()方法的Panel()方法。因此,在1秒后,您将添加1000个MouseListener添加到您的面板。这显然是错误的。应该在类的构造函数中添加MouseListener。

    不需要“co”变量(如果需要它不会是静态的)。所有Swing组件都支持setForeground()方法来设置绘制文本的颜色。在您的情况下,您正在绘制一个形状,但是当您想要更改颜色时,仍然可以使用setForeground()方法。然后在您的绘画代码中,您只需使用:

    //g.setColor(co);
    g.setColor(getForeground());
    

    由于您已将MouseListener添加到面板,因此无需检查鼠标单击的点。只有在单击面板时才会生成该事件。所以你需要做的就是使用setForeground(...)来获得你想要的颜色。您甚至不需要调用重绘,因为当您更改其中一个属性时,Swing足够聪明地重新绘制自己。