开发者

Custom Java Mouse Listeners?

开发者 https://www.devze.com 2023-01-23 04:47 出处:网络
First off, I came to Java as a website programmer. In JavaScript, all you have to do to add a mousemove, mouseover, or click event is call an addEventListener function. From my limited experience with

First off, I came to Java as a website programmer. In JavaScript, all you have to do to add a mousemove, mouseover, or click event is call an addEventListener function. From my limited experience with Java, you can't just implement the MouseListener interface from any object.

Basically, what I have so far is a JPanel, that paints some shapes (a CustomShape object with a paint method) that have x/y/width/height values. I want to add some type of mouse listener to the shape object, so that I can fire move/roll/click events for the shape. Just implementing the MouseListener interface to the CustomShape object doesn't work (for what I suppose are obvious reasons). I've looked up how to design custom event listeners, but it doesn't seem as though making a custom mouse listener is possible.

I eventually resorted to adding the mouse listener to the JPanel, and then looping through all the shape objects. If the shape object had a 'listener' attached, and the mouse coordinates verified the mouse event had occurred, it fired the method. Initially, it was fine, but as the application got more developed, it started getting really really messy. Plus, I would never be able to copy over the shape objects/interfaces to another application without copying a bunch of code.

As a simple illustration: (the actual code is quite large)

Interface CustomShape{
    int width, height, x, y;
    void paint(Graphics g);
}

public class StarShape implements CustomShape{
    int width, height, x, y;
    public StarShape(){
        width = 100;
        height = 100;
        x = 50;
        y = 50;
    }
    void paint(Graphics g){
        g.setCo开发者_StackOverflowlor(Color.black);
        g.draw(new Rectangle(x,y,width,height));
    }
}

public class Main extends JPanel{
    StarShape check = new StarShape();
    public Main(){  }
    @Override
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        check.paint(g);
    }
}

So, I was wondering if there is a clean way of implementing some type of mouse listener for a 'hand-drawn' shape.


To be able to receive events, your "Shape" objects should extend java.awt.Component (or javax.swing.JComponent). Then you can add them to the JPanel as a child, and they'll receive events and you can add listeners directly to them.

The way you're doing, you have to manually track the position of your shapes in the JPanel. You'd add the mouse listener to the panel itself, and depending on the the x/y coordinates of the event you get, call some method on the shape to handle the event. Which is pretty much reimplementing what the base AWT/Swing classes will do for you.


My approach to doing what you're trying to do. Compile, run, read :-)

(Note: you can copy every single line of code below into a single file Example01.java. Compile it and run it.)

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

public class Example01 {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame jf = new JFrame();
                MainPanel mainPanel = new MainPanel();
                jf.add(mainPanel);
                jf.setSize(640, 480);
                jf.setLocationRelativeTo(null);
                jf.setVisible(true);
            }
        });
    }
}

class MainPanel extends JPanel {
    StarShape check1 = new StarShape();
    StarShape check2 = new StarShape();

    public MainPanel() {
        check1.setName("check1");
        check2.setName("check2");
        check1.addMouseListener(new MyMouseListener(check1));
        check2.addMouseListener(new MyMouseListener(check2));
        this.add(check1);
        this.add(check2);
    }
}

class StarShape extends JComponent {
    public StarShape() {
        this.setPreferredSize(new Dimension(100, 100));
    }

    @Override
    protected void paintComponent(Graphics g) {
        g.setColor(Color.black);
        Graphics2D g2d = (Graphics2D) g;
        int x = 0;
        int y = 0;
        int width = this.getWidth() - 1;
        int height = this.getHeight() - 1;
        g2d.draw(new Rectangle(x, y, width, height));
    }
}

class MyMouseListener implements MouseListener {
    private final JComponent component;

    public MyMouseListener(JComponent component) {
        this.component = component;
    }

    public void mouseClicked(MouseEvent e) {
        System.out.println("mouseClicked: " + component.getName());
    }

    public void mouseEntered(MouseEvent e) {
        System.out.println("mouseEntered: " + component.getName());
        Dimension preferredSize = component.getPreferredSize();
        preferredSize.height += 20;
        preferredSize.width += 20;
        component.setPreferredSize(preferredSize);
        component.invalidate();
        SwingUtilities.getWindowAncestor(component).validate();
    }

    public void mouseExited(MouseEvent e) {
        System.out.println("mouseExited: " + component.getName());
        Dimension preferredSize = component.getPreferredSize();
        preferredSize.height -= 20;
        preferredSize.width -= 20;
        component.setPreferredSize(preferredSize);
        component.invalidate();
        SwingUtilities.getWindowAncestor(component).validate();
    }

    public void mousePressed(MouseEvent e) {
        System.out.println("mousePressed: " + component.getName());
    }

    public void mouseReleased(MouseEvent e) {
        System.out.println("mouseReleased: " + component.getName());
    }
}


What you could do is have the shape extend JPanel.

public abstract class CustomShape extends JPanel {

    public CustomShape(){
        setOpaque(false);
    }

    public abstract void paintShape(Graphics g);

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        paintShape(g);
    }

}

Then you can add the listeners directly on the shapes.

You will then need to create your parent JPanel, and set its LayoutManager to null. And then you will need to manually set the location of the Shape on the parent.

Read a little more about manually laying out components here. And, if you don't like this approach, check out my answer to this question. It talks about moving colored rectangles around the screen with your mouse.

0

精彩评论

暂无评论...
验证码 换一张
取 消