I want to make a table filled with hexagonal JButtons and preferably place it over a background image (e.g. Civilization games).
Is there any way to do it? I've tried and searched for many solutions with not much success, any help would be greatly appreciated!
Thank you in advance!
CodePudding user response:
I'm always a bit wary about extending from something like JButton
, it itself is a very complex UI component, which a lot of functionality which can come back and byte you.
I might consider simply starting with JPanel
and creating the functionality that's required, but in either case, it kind of comes down to basically the same core concept.
You need to be able to determine the size of the button which will best fit the content and the border and this might take some tweaking to get right, then painting the desired shape and content and finally responding to appropriate events.
The following is a VERY basic example, which is based on
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.RenderingHints;
import java.awt.geom.Path2D;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
HexagonButton btn = new HexagonButton("Hello");
setLayout(new GridBagLayout());
add(btn);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.dispose();
}
}
public class HexagonButton extends JButton {
private HexagonPath hexagonPath;
public HexagonButton(String text) {
super(text);
applyDefaults();
}
public HexagonButton(Icon icon) {
super(icon);
applyDefaults();
}
public HexagonButton(String text, Icon icon) {
super(text, icon);
applyDefaults();
}
public HexagonButton(Action action) {
super(action);
applyDefaults();
}
@Override
public void invalidate() {
hexagonPath = null;
super.invalidate();
}
protected int getMaxDimension() {
Dimension size = super.getPreferredSize();
return Math.max(size.width, size.height);
}
@Override
public Dimension getPreferredSize() {
int maxDimension = getMaxDimension();
return new Dimension(maxDimension, maxDimension);
}
@Override
public Dimension getMaximumSize() {
return getPreferredSize();
}
@Override
public Dimension getMinimumSize() {
return getPreferredSize();
}
protected void applyDefaults() {
setBorderPainted(false);
setFocusPainted(false);
}
protected HexagonPath getHexagonPath() {
if (hexagonPath == null) {
hexagonPath = new HexagonPath(getMaxDimension() - 1);
}
return hexagonPath;
}
@Override
protected void paintBorder(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
HexagonPath path = getHexagonPath();
g2d.setColor(getForeground());
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
g2d.draw(path);
g2d.dispose();
}
@Override
public Color getBackground() {
if (getModel().isArmed()) {
return Color.BLUE;
}
return super.getBackground();
}
@Override
public Color getForeground() {
if (getModel().isArmed()) {
return Color.WHITE;
}
return super.getForeground();
}
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
g2d.setColor(getBackground());
g2d.fill(getHexagonPath());
super.paintComponent(g2d);
g2d.dispose();
}
protected class HexagonPath extends Path2D.Double {
public HexagonPath(double size) {
double centerX = size / 2d;
double centerY = size / 2d;
for (double i = 0; i < 6; i ) {
double angleDegrees = (60d * i) - 30d;
double angleRad = ((float) Math.PI / 180.0f) * angleDegrees;
double x = centerX ((size / 2f) * (double) Math.cos(angleRad));
double y = centerY ((size / 2f) * (double) Math.sin(angleRad));
if (i == 0) {
moveTo(x, y);
} else {
lineTo(x, y);
}
}
closePath();
}
}
}
}