继承JButton自定义绘制后,如何限制ActionListener仅在按钮区域触发?
问题描述
我尝试在JFrame上绘制Windows 11风格按钮,绘制效果良好,但无法正确为其添加ActionListener。以下是我的代码:
public class MyButton extends JButton implements MouseListener, ActionListener { public MyButton(String text) { //super(label); enableInputMethods(true); addMouseListener(this); setFocusPainted(false); setBorderPainted(false); buttonText = text; } @Override protected void paintComponent(Graphics g) { //super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; FontMetrics metrics = g2.getFontMetrics(Constants.arialFont); g2.setStroke(new BasicStroke(2.0f)); g2.setFont(Constants.arialFont); g2.setPaint(Constants.buttonNormal); rect = new RoundRectangle2D.Double(0, 0, metrics.stringWidth(buttonText) + 20, 27, 10, 10); g2.fill(rect); g2.setPaint(Constants.fontColor); g2.drawString(buttonText, Functions.getMiddleFromX(g2, rect, buttonText), Functions.getMiddleFromY(g2, rect, buttonText)); }
我尝试按如下方式添加MouseListener:
@Override public void mouseClicked(MouseEvent e) { // Check if the click is on the button. Point p = e.getPoint(); if(rect.contains(p)) System.out.println("Triangle contains point"); else { return; } }
但运行以下代码时,点击JFrame任意区域都会打印"Action Performed!":
MyButton myButton = new MyButton("Epic button!"); myButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("Action Performed!"); } }); frame.add(myButton);
请问如何过滤事件,仅在点击RoundRectangle2D.Double区域时执行操作?
解决方案
问题核心是JButton默认以矩形作为可点击区域,哪怕你绘制了圆角样式,组件依然会响应整个矩形范围内的点击,甚至组件大小不匹配时,空白区域也会触发事件。按以下步骤修复:
匹配组件尺寸与圆角矩形
在构造方法中根据文本计算按钮尺寸,设置组件的固定大小,让组件边界和绘制的圆角区域一致:public MyButton(String text) { enableInputMethods(true); setFocusPainted(false); setBorderPainted(false); buttonText = text; // 计算并设置按钮尺寸 FontMetrics metrics = getFontMetrics(Constants.arialFont); int btnWidth = metrics.stringWidth(buttonText) + 20; int btnHeight = 27; setPreferredSize(new Dimension(btnWidth, btnHeight)); setMinimumSize(new Dimension(btnWidth, btnHeight)); setMaximumSize(new Dimension(btnWidth, btnHeight)); }重写
contains方法限制点击区域JComponent的contains方法决定组件是否识别某个点在自身范围内,重写它来判断点击点是否在你的圆角矩形内:private RoundRectangle2D rect; @Override public boolean contains(int x, int y) { return rect != null && rect.contains(x, y); }确保
rect在paintComponent中正确初始化,这个方法才能正常工作。移除自定义MouseListener,使用原生事件
重写contains后,JButton的原生事件机制会自动过滤圆角外的点击,直接使用addActionListener即可,无需自己编写MouseListener判断逻辑。恢复
super.paintComponent(g)调用(推荐)
注释掉父类的绘制方法可能导致背景、焦点状态等异常,建议保留该调用,再绘制自定义样式:@Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; FontMetrics metrics = g2.getFontMetrics(Constants.arialFont); g2.setStroke(new BasicStroke(2.0f)); g2.setFont(Constants.arialFont); g2.setPaint(Constants.buttonNormal); rect = new RoundRectangle2D.Double(0, 0, metrics.stringWidth(buttonText) + 20, 27, 10, 10); g2.fill(rect); g2.setPaint(Constants.fontColor); g2.drawString(buttonText, Functions.getMiddleFromX(g2, rect, buttonText), Functions.getMiddleFromY(g2, rect, buttonText)); }
内容的提问来源于stack exchange,提问作者user21603351
相关产品推荐
相关产品推荐

