在 Graphics2D 中结合 MouseListeners 和多边形

Combining MouseListeners with Polygons in Graphics2D

我已尝试为我选择的数据 class 扩展 Polygon(实施 MouseListener)。我在父级 JPanel 中的 paintComponent 覆盖正在使用 .fillPolygon 渲染扩展的 Polygon class(我称之为 Hexagon) - 它渲染得很好!

但它不允许我与它的代码中实现的 MouseListener 进行交互。有没有我遗漏的阶段?

四处寻找灵感,得出了这个:

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

不幸的是,这限制了应用程序 - 它可以很好地处理事件点击,但是对于使用悬停事件,应用于父容器的 MouseListener 意味着它只跟踪进入/退出该容器。对于 Shape within 那个容器,没有办法让它在进入/退出时工作。

Hexagon(摘要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(具体子class):

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 我的习惯 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();
}

您将不得不为此使用 mouseMoved()。然后您可以检查鼠标光标下当前是哪个形状并做出相应的反应。你可以这样做:

 // 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();
     }
 }

由于contains()Shape的一种方法,它适用于任何形状。由于您的形状实现了 MouseListener,因此您实现了 enter/exit 功能并将鼠标事件传递给它们。