Reputation: 1168
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();
}
Upvotes: 1
Views: 225
Reputation: 1922
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.
Upvotes: 1