Search code examples
javaimagemap

Image mapping like feature in Java swing, Points vs GeneralPath


My gaol is to draw several images using 2D graphics in a paintComponent() method. However, I'm not sure how I could add a MouseListener such that each image would know if it was selected.

My solution thus far is too simply record the coordinates of the mouse click, and see if they are contained within the boundaries of each of the images. However this will be difficult with images that have more complex boundaries.

Another option would be too create simple shapes and place them over the images, but again images with more complex boundaries will be difficult. In another discussion on SO found here, someone mentioned using GeneralPath to draw more complex shapes. I have never played with is, but this seems encouraging.

Of these 2 options, what seems to be the best solution, or are there other recommendations


Solution

  • Are you images painted on top of one another or are they drawn separately.

    If they are drawn separately, then you should do the custom painting on a JComponent. Then you can do the drawing by using the GeneralPath. You will also need to implement the contains(...) method by checking if the mouseclick is contained in the GeneralPath. If the contains() method is implemented properly then the MouseListener will respond properly.

    Here is a simpler example:

    import java.awt.*;
    import java.awt.event.*;
    import java.awt.geom.*;
    import javax.swing.*;
    
    public class RoundButton extends JButton {
        public RoundButton(String label) {
            super(label);
    
            // These statements enlarge the button so that it
            // becomes a circle rather than an oval.
            Dimension size = getPreferredSize();
            size.width = size.height = Math.max(size.width, size.height);
            setPreferredSize(size);
    
            // This call causes the JButton not to paint the background.
            // This allows us to paint a round background.
            setContentAreaFilled(false);
        }
    
        // Paint the round background and label.
        protected void paintComponent(Graphics g) {
        if (getModel().isArmed()) {
                // You might want to make the highlight color
                // a property of the RoundButton class.
                g.setColor(Color.lightGray);
            } else {
                g.setColor(getBackground());
            }
        g.fillOval(0, 0, getSize().width-1, getSize().height-1);
    
            // This call will paint the label and the focus rectangle.
        super.paintComponent(g);
        }
    
        // Paint the border of the button using a simple stroke.
        protected void paintBorder(Graphics g) {
            g.setColor(getForeground());
            g.drawOval(0, 0, getSize().width-1, getSize().height-1);
        }
    
        // Hit detection.
        Shape shape;
        public boolean contains(int x, int y) {
            // If the button has changed size, make a new shape object.
            if (shape == null || !shape.getBounds().equals(getBounds())) {
                shape = new Ellipse2D.Float(0, 0, getWidth(), getHeight());
            }
            return shape.contains(x, y);
        }
    
        // Test routine.
        public static void main(String[] args) {
            // Create a button with the label "Jackpot".
            JButton button = new RoundButton("Jackpot");
            button.setBackground(Color.green);
            button.setBounds(0, 0, 100, 100);
    
            JButton button2 = new RoundButton("Jackpot2");
            button2.setBackground(Color.red);
            button2.setBounds(50, 50, 100, 100);
    
            // Create a frame in which to show the button.
            JFrame frame = new JFrame();
            frame.getContentPane().setBackground(Color.yellow);
            frame.getContentPane().setLayout(null);
            frame.getContentPane().add(button);
            frame.getContentPane().add(button2);
    //        frame.getContentPane().setLayout(new FlowLayout());
            frame.setSize(200, 200);
            frame.setVisible(true);
    
            MouseListener mouseListener = new MouseAdapter() {
                public void mouseEntered( MouseEvent e )
                {}
    
                public void mouseExited( MouseEvent e )
                {}
    
                public void mouseClicked( MouseEvent e )
                {
                    System.out.println( "clicked " );
                }
    
                public void mousePressed( MouseEvent e )
                {
                    System.out.println( "pressed " );
                }
    
                public void mouseReleased( MouseEvent e )
                {
                    System.out.println( "released " );
                }
            };
            button.addMouseListener( mouseListener );
    
        }
    }