在 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 功能并将鼠标事件传递给它们。
我已尝试为我选择的数据 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 功能并将鼠标事件传递给它们。