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 注册没有发生的点击的主要内容,如果未能解决你的问题,请参考以下文章
当在子组件中添加其他 MouseListener 时,父组件的 MouseListener 在子组件中不起作用