repaint 导致 mouseListener 注册没有发生的点击

Posted

技术标签:

【中文标题】repaint 导致 mouseListener 注册没有发生的点击【英文标题】:repaint causes mouseListener to register clicks that didn't happen 【发布时间】:2015-06-09 18:45:19 【问题描述】:

我正在做一个禁止使用 JButton 的程序。我被要求在 awt 矩形上使用鼠标事件侦听器。点击按钮的结果应该是:

将 10 添加到另一个类中的变量 重新绘制一个代表燃油表的矩形

问题是,当我将 repaint 方法放在 mouseClicked 侦听器的末尾时,在第一次单击之后,侦听器会注册多次单击而不是一次。这是一个实现我使用的相同类型的按钮替换的程序(在 StackExchange 上找到):

import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.*;

public class Gui2 extends JFrame 
    JFrame frame = new JFrame();
    MyDrawPanel drawpanel = new MyDrawPanel();

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

    public void go() 

        frame.getContentPane().add(drawpanel);
        // frame.addMouseListener(this);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(300, 300);
        frame.setVisible(true);

    



class MyDrawPanel extends JComponent implements MouseListener 
    private boolean mouseClicked = false;

    public void paintComponent(Graphics g) 

        int red = (int) (Math.random() * 255);
        int green = (int) (Math.random() * 255);
        int blue = (int) (Math.random() * 255);
        Color startrandomColor = new Color(red, green, blue);

        red = (int) (Math.random() * 255);
        green = (int) (Math.random() * 255);
        blue = (int) (Math.random() * 255);
        Color endrandomColor = new Color(red, green, blue);

        Graphics2D g2d = (Graphics2D) g;
        this.addMouseListener(this);
        GradientPaint gradient = new GradientPaint(70, 70, startrandomColor,
                150, 150, endrandomColor);

        g2d.setPaint(gradient);
        g2d.fillOval(70, 70, 100, 100);

    

    @Override
    public void mouseClicked(MouseEvent e) 
        if ((e.getButton() == 1)
                && (e.getX() >= 70 && e.getX() <= 170 && e.getY() >= 70 && e
                .getY() <= 170)) 
            mouseClicked = true;
            this.repaint();
            if(mouseClicked == true)
                System.out.println("click");
            
            // JOptionPane.showMessageDialog(null,e.getX()+ "\n" + e.getY());
        

    

    @Override
    public void mouseEntered(MouseEvent e) 
        // TODO Auto-generated method stub

    

    @Override
    public void mouseExited(MouseEvent e) 
        // TODO Auto-generated method stub

    

    @Override
    public void mousePressed(MouseEvent e) 
        // TODO Auto-generated method stub

    

    @Override
    public void mouseReleased(MouseEvent e) 
        // TODO Auto-generated method stub

    


当单击框架中的椭圆时,控制台上会打印一次“单击”。当它由于某种原因被第二次点击时,它会打印 2 次“点击”。对于第三次单击,它会打印 3,依此类推。为什么 repaint 方法会这样做?如何在 awt 椭圆上使用它而不注册多次点击?

【问题讨论】:

请参阅编辑回答。 @AndrewThompson:因为它在项目规范中。 【参考方案1】:

不要在 paintComponent 方法中添加 MouseListener,因为这会继续向您的组件添加 多个 MouseListener,因此每次随后的鼠标单击,都会多次调用随机化和重绘,不是你想要的。在类的构造函数中添加一次,你的问题就解决了。请记住,paintComponent 方法应该仅用于绘画和绘画,而不是用于更改组件、添加侦听器、读取图像或其他任何事情。事实上,我会在 MouseListener 中设置我的随机颜色,而不是在 paintComponent 中,否则当你调整 GUI 大小时颜色会改变。顺便说一下,为什么是布尔变量?另外,不要忘记将 super.paintComponent 调用添加到您的paintComponent 覆盖。我也会使用mousePressed,而不是mouseClicked,因为mouseClicked 可能不可靠。例如:

import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import javax.swing.*;

public class Gui2 
   JFrame frame = new JFrame();
   MyDrawPanel drawpanel = new MyDrawPanel();

   public static void main(String[] args) 
      SwingUtilities.invokeLater(new Runnable() 
         public void run() 
            Gui2 gui = new Gui2();
            gui.go();
         
      );
   

   public void go() 
      frame.getContentPane().add(drawpanel);
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   


class MyDrawPanel extends JComponent 
   private static final int PREF_W = 240;
   private static final int PREF_H = PREF_W;
   private static final double RGB_MAX = 255;
   private static final double ELLIPSE_X = 70;
   private static final double ELLIPSE_WIDTH = PREF_W - 2 * ELLIPSE_X;
   private int red;
   private int green;
   private int blue;
   private Color startrandomColor;
   private Color endrandomColor;
   private Ellipse2D ellipse = new Ellipse2D.Double(ELLIPSE_X, ELLIPSE_X,
         ELLIPSE_WIDTH, ELLIPSE_WIDTH);

   public MyDrawPanel() 
      addMouseListener(new MyMouseAdapter());
      setRandomGradient();
   

   private void setRandomGradient() 
      red = (int) (Math.random() * RGB_MAX);
      green = (int) (Math.random() * RGB_MAX);
      blue = (int) (Math.random() * RGB_MAX);
      startrandomColor = new Color(red, green, blue);
      red = (int) (Math.random() * RGB_MAX);
      green = (int) (Math.random() * RGB_MAX);
      blue = (int) (Math.random() * RGB_MAX);
      endrandomColor = new Color(red, green, blue);
   

   public void paintComponent(Graphics g) 
      super.paintComponent(g);
      Graphics2D g2d = (Graphics2D) g;
      g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
      GradientPaint gradient = new GradientPaint(70, 70, startrandomColor, 150,
            150, endrandomColor);

      g2d.setPaint(gradient);
      g2d.fill(ellipse);
   

   @Override
   public Dimension getPreferredSize() 
      if (isPreferredSizeSet()) 
         return super.getPreferredSize();
      
      return new Dimension(PREF_W, PREF_H);
   

   private class MyMouseAdapter extends MouseAdapter 
      @Override
      public void mousePressed(MouseEvent e) 
         if (ellipse.contains(e.getPoint())) 
            setRandomGradient();
            repaint();
         
      
   

另请注意,如果您使用 Ellipse2D,则 MouseListener 中的 if 块会大大简化,这会大大降低您遇到难以发现的有害错误的风险:

  @Override
  public void mousePressed(MouseEvent e) 
     if (ellipse.contains(e.getPoint())) 
        setRandomGradient();
        repaint();
     
  

【讨论】:

非常感谢。我曾尝试将侦听器与paintComponent 分开,但我从未想过要使用继承MouseAdapter 类的类。

以上是关于repaint 导致 mouseListener 注册没有发生的点击的主要内容,如果未能解决你的问题,请参考以下文章

repaint和reflow

javascript性能优化-repaint和reflow

reflow 和 repaint

当在子组件中添加其他 MouseListener 时,父组件的 MouseListener 在子组件中不起作用

MouseListener 不调用 mouseClicked 方法

使用 acm.graphics 时 mouseListener 的语法是啥