Combining MouseListeners with Polygons in Graphics2D

限于喜欢 提交于 2019-12-11 13:39:05

问题


I've tried extending Polygon for my data class of choice (implementing MouseListener). My paintComponent override in the parent JPanel is rendering the extended Polygon class (I called it Hexagon) with .fillPolygon - it renders fine!

But it doesn't let me interact with the MouseListener implemented in the code of it. Is there a stage I'm missing somewhere?

Looked around for inspiration, arrived at this:

https://docs.oracle.com/javase/tutorial/2d/advanced/user.html

Unfortunately this limits application - it handles event clicks well, but for using hover events, the MouseListener being applied to the parent container means that it only tracks enter / exit to that container. There's no way to get it to work on enter / exit for a Shape within that container.

Hexagon (abstract class):

import java.awt.Polygon;
import java.util.ArrayList;

import spare.Theme;

public abstract class Hexagon extends Polygon {

    private static final long serialVersionUID = 1L;

    public enum HEX_TYPE { ALIVE, INFECTED, DEAD };
    public enum SELECTION_TYPE { SELECTED, GROUPED, NONE };

    private int hexEdgeWidth = 20;
    private int hexBorderWidth = 3;
    private ArrayList<Hexagon> children;

    private Theme theme;

    private boolean hover = false;
    private boolean selected = false;

    public ArrayList<Hexagon> getChildren() {
        return children;
    }

    public int getHexEdgeWidth() {
        return hexEdgeWidth;
    }

    public void setHexEdgeWidth(int hexEdgeWidth) {
        this.hexEdgeWidth = hexEdgeWidth;
    }

    public int getHexBorderWidth() {
        return hexBorderWidth;
    }

    public void setHexBorderWidth(int hexBorderWidth) {
        this.hexBorderWidth = hexBorderWidth;
    }

    public void setChildren(ArrayList<Hexagon> children) {
        this.children = children;
    }

    public Theme getTheme() {
        return theme;
    }

    public void setTheme(Theme theme) {
        this.theme = theme;
    }

    public boolean isHover() {
        return hover;
    }

    public void setHover(boolean hover) {
        this.hover = hover;
    }

    public boolean isSelected() {
        return selected;
    }

    public void setSelected(boolean selected) {
        this.selected = selected;
    }

}

BasicHexagon (concrete subclass):

import java.awt.Color;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import spare.Theme;

public class BasicHexagon extends Hexagon implements MouseListener {

    private static final long serialVersionUID = 1L;

    public BasicHexagon() {
        setChildren(null);
        int n = 6;
        int size = getHexEdgeWidth();
        for (int i = 0; i < n; i++) {
            // x + radius * cosine of angle * iteration in radians
            // y + radius * sine of angle * iteration in radians
            addPoint(
                    (int) (size * Math.cos(Math.toRadians(360 / n * i))),
                    (int) (size * Math.sin(Math.toRadians(360 / n * i))));
        }

        setTheme(new Theme(
                new Color(255, 255, 255, 180),      // primary
                new Color(255, 255, 255, 255),      // primary hover
                new Color(255, 0, 0, 180),          // secondary
                new Color(255, 0, 0, 255),          // secondary hover
                new Color(255, 255, 100, 255),      // border
                new Color(255, 255, 100, 255)));    // text
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        System.out.println("clicked");  
        BasicHexagon bH = (BasicHexagon) e.getSource();
        if(bH.isSelected()) {
            bH.setSelected(false);
        } else {
            bH.setSelected(true);
        }
    }

    @Override
    public void mousePressed(MouseEvent e) {
    }

    @Override
    public void mouseReleased(MouseEvent e) {
    }

    @Override
    public void mouseEntered(MouseEvent e) {
        BasicHexagon bH = (BasicHexagon) e.getSource();
        bH.setHover(true);
        System.out.println("in the zone");
    }

    @Override
    public void mouseExited(MouseEvent e) {
        BasicHexagon bH = (BasicHexagon) e.getSource();
        bH.setHover(false);
        System.out.println("fleeing");
    }

}

paintComponent for my custom JPanel:

@Override
public void paintComponent(Graphics g) {
    Toolkit.getDefaultToolkit().sync();
    super.paintComponent(g);
    switch (getGameState()) {
    case IN_GAME:
        doIngameDrawing(g);
        break;
    case END_GAME:
        break;
    case PAUSED:
        break;
    case PRE_GAME:
        break;
    default:
        break;
    }
}

private void doIngameDrawing(Graphics g) {
    Graphics2D g2d = (Graphics2D) g;
    for(Hexagon h : getTiles()) {
        h.translate(getPreferredSize().width / 2, getPreferredSize().height / 2);
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
                RenderingHints.VALUE_ANTIALIAS_ON);
        if(h.isHover() && h.isSelected()) {
            g2d.setColor(h.getTheme().getSecondaryHover());
            g2d.fillPolygon(h);
        } else if(h.isHover()) {
            g2d.setColor(h.getTheme().getPrimaryHover());
            g2d.fillPolygon(h);
        } else if(h.isSelected()) {
            g2d.setColor(h.getTheme().getSecondary());
            g2d.fillPolygon(h);
        } else {
            // draw the normal colours;
            g2d.setColor(h.getTheme().getPrimary());
            g2d.fillPolygon(h);
        }

        g2d.setStroke(new BasicStroke(h.getHexBorderWidth()));
        g2d.setColor(h.getTheme().getBorder());
        g2d.drawPolygon(h);         
        if(h.getChildren() != null) {
            // child rendering goes here
        }
    }

    g2d.dispose();
}

回答1:


You will have to use mouseMoved() for that. Then you can check which shape is currently under the mouse cursor and react accordingly. You could do something like this:

 // This is in your custom JPanel, which for simplicity is also its own MouseListener.
 // Assuming getHexagons() returns Hexagon[].
 // Assuming Hexagon implements MouseListener.

 private Hexagon lastHovered;

 public void mouseMoved(MouseEvent e) {
     Hexagon current = null;
     boolean changed = false;
     for (Hexagon hex : getHexagons()) {
         if (hex.contains(e.getX(), e.getY())) {
             current = hex;
             break;
         }
     }
     if (lastHovered != current) {
         changed = true;
         if (lastHovered != null) {
             lastHovered.mouseExited(e);
         }
         if (current != null) {
             current.mouseEntered(e);
         }
     }
     lastHovered = current;
     if (changed) {
         repaint();
     }
 }

Since contains() is a method of Shape, it works for any shape. Since your shapes implement MouseListener, you implement the enter/exit functionality and pass mouse events to them.



来源:https://stackoverflow.com/questions/32848552/combining-mouselisteners-with-polygons-in-graphics2d

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!