Java 向绘制的组件添加鼠标侦听器

Java 向绘制的组件添加鼠标侦听器,java,jframe,jlabel,Java,Jframe,Jlabel,我有以下课程: import javax.swing.*; import java.awt.*; public class Frame extends JFrame { public Frame() { // This label draws two black rectangles to the screen. JLabel label = new JLabel() { @Override publi

我有以下课程:

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

public class Frame extends JFrame {

    public Frame() {

        // This label draws two black rectangles to the screen.
        JLabel label = new JLabel() {
            @Override
            public void paintComponent(Graphics g) {
                g.clearRect(0, 0, getWidth(), getHeight()); // clears the screen
                g.fillRect(50, 50, 50, 75); // draws first rect
                g.fillRect(150, 50, 50, 75); // draws second rect
            }
        };

        // adds the label to the frame
        add(label);

        // frame properties
        setSize(250, 200);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    }
}

此类将绘制到屏幕的矩形。一切正常。但是我想在两个矩形中都添加一个鼠标侦听器,这样我就知道用户何时单击两个矩形中的一个。这只是一个例子。也可能有二十个或更多的矩形,而不仅仅是两个。如何为我绘制的每个矩形添加鼠标侦听器?使用
mouseClicked()
方法(由MouseListener实现),我希望获得单击的矩形。我该怎么做呢?

您可以像这样为标签添加鼠标侦听器

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

public class MyFrame extends JFrame {
    public MyFrame() {

        // This label draws two black rectangles to the screen.
        JLabel label = new JLabel() {

            @Override
            public void paintComponent(Graphics g) {
                g.clearRect(0, 0, getWidth(), getHeight()); // clears the screen
                g.fillRect(50, 50, 50, 75); // draws first rect
                g.fillRect(150, 50, 50, 75); // draws second rect
            }
        };

        // adds the label to the frame
        add(label);

        label.addMouseListener(new java.awt.event.MouseAdapter() {

            public void mouseClicked(java.awt.event.MouseEvent evt) {
                int x = evt.getX();
                int y = evt.getY();

                if (x >= 50 && x < 100 && y >= 50 && y <= 125) {
                    rectangleClicked(1);
                } 
                else if (x >= 150 && x < 200 && y >= 50 && y <= 125) {
                    rectangleClicked(2);
                }

            }
        });
        // frame properties
        setSize(250, 200);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    }

    public void rectangleClicked(int r) {
        System.out.println("Rectangle " + r + " clicked.");
    }

    public static void main(String args[]) {

        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                new MyFrame().setVisible(true);
            }
        });
    }
}
import javax.swing.*;
导入java.awt.*;
公共类MyFrame扩展了JFrame{
公共MyFrame(){
//此标签在屏幕上绘制两个黑色矩形。
JLabel标签=新的JLabel(){
@凌驾
公共组件(图形g){
g、 clearRect(0,0,getWidth(),getHeight());//清除屏幕
g、 fillRect(50,50,50,75);//绘制第一个矩形
g、 fillRect(150,50,50,75);//绘制第二个矩形
}
};
//将标签添加到框架中
添加(标签);
label.addMouseListener(新java.awt.event.MouseAdapter(){
public void mouseClicked(java.awt.event.MouseEvent evt){
int x=evt.getX();
int y=evt.getY();

如果(x>=50&&x<100&&y>=50&&y=150&&x<200&&y>=50&&y首先,我建议使用javafx,这种情况下最好使用图形场景

对于swing,您可以创建一个awt.Component,并自行处理布局/位置

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

/**
 *  Created by matt on 8/9/15.
 */
public class ClickableTest {

    public static void main(String[] args){

        JFrame frame = new JFrame("painting example");

        JPanel panel = new JPanel();

        Component panelB = new JPanel(){
            Shape circle = new Ellipse2D.Double(0,0,100, 100);
            public boolean contains(int x, int y){
                return circle.contains(x,y);
            }

            @Override
            public void paintComponent(Graphics g){
                g.setColor(Color.BLUE);
                ((Graphics2D)g).fill(circle);
            }
        };
        panelB.addMouseListener(new MouseAdapter(){
            public void mouseClicked(MouseEvent evt){
                System.out.println("clicked");
            }
        });

        //now swing will not modify the size of panel be.
        panel.setLayout(null);
        panel.add(panelB);

        panelB.setBounds(300, 300, 100, 100);
        frame.setContentPane(panel);
        frame.setSize(600, 600);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);

    }

}
这当然可以改进

  • 不要扩展用于自定义绘制的JLabel。您可以扩展
    JPanel
    JComponent

  • 不要在paintComponent()方法中硬编码矩形的绘制

  • 在进行自定义绘制的类的构造函数中,需要创建一个
    ArrayList
    来保存要绘制的
    矩形。类似于:

    public RectanglePanel extends JPanel
    {
        List<Rectangles> rectangles = new ArrayList<Rectangles>();
    
        public RectanglePanel()
        {
            rectangles.add( new Rectangle(50, 50, 50, 75) );
            rectangles.add( new Rectangle(150, 50, 50, 75) );
        }
    }
    
    现在在
    MouseListener
    中,您可以使用
    Rectangle
    contains(…)
    方法查看单击了哪个
    Rectangle

    @Override
    protected void mouseClicked(MouseEvent e)
    {
        for (Rectangle r: rectangles)
        {
            if (r.contains(e.getPoint())
               // do something
        }
    }
    

    这是一个更加灵活的解决方案,允许您用一行代码添加更多的矩形。

    将listner添加到lable并检测鼠标单击的矩形coordinates@FastSnail你能通过发布一段代码来解释这一点吗?@DejoriDavid:创建一个名为
    Shape
    抽象类。然后创建你真正的形状例如
    矩形
    正方形
    圆形
    或任何其他形状都必须
    扩展该形状。创建名为
    公共布尔isPointWithinArea(点p)的抽象方法;
    用于Shape类。因此,每个真实形状都必须实现此方法。使用一些数学知识,您可以为每个真实形状实现此方法。然后,正如FastSnail所说,您应该向正在绘制形状的框架中添加一个
    mouseListener
    。然后在该mouseListener中,您可以获得单击点(x,y)并将其传递给形状。这对单击和移动事件非常有效,但对enter和exit不起作用,因为对于JPanel,enter和exit只调用一次。有什么建议/想法如何在鼠标进入/退出绘制的矩形时使其工作吗?您可以使用MouseMotionListener并处理mouseMoved事件。逻辑基本上与mouseClicked事件。也就是说,您仍然需要遍历所有矩形,以确定您是刚输入一个矩形还是退出一个矩形。感谢@camickr。我通过使用mouseMoved事件矩形,将它们存储在一个集合中,并计算上一个矩形和下一个矩形之间的差异,成功地重新创建了MouseEnted/mouseExited事件ew移动矩形。这样我可以非常一致地跟踪鼠标插入/鼠标退出事件。
    @Override
    protected void mouseClicked(MouseEvent e)
    {
        for (Rectangle r: rectangles)
        {
            if (r.contains(e.getPoint())
               // do something
        }
    }