Так что это вариант, который работает. Снова сначала класс Button:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Point;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JButton;
import javax.swing.SwingUtilities;
public class MyCircleButton extends JButton implements MouseListener {
public MyCircleButton(String text, double xCenter, double yCenter, double rOuter, double rInner,
double start, double extend) {
super(text);
this.xCenter = xCenter;
this.yCenter = yCenter;
this.xOffset = xCenter - rOuter;
this.yOffset = yCenter - rOuter;
this.rOuter = rOuter;
this.rInner = rInner;
this.angStart = start;
this.angSize = extend;
int fontSize = (int) ((rOuter - rInner) * 0.5);
setFont(new Font("Arial", Font.BOLD, fontSize));
this.addMouseListener(this);
setBorderPainted(false);
setContentAreaFilled(false);
calcShape();
calcText();
}
@Override
public boolean contains(int x, int y) {
return shape.contains(x, y);
}
@Override
public int getHeight() {
return shape.getBounds().height;
}
@Override
public int getWidth() {
return shape.getBounds().width;
}
@Override
public int getX() {
return shape.getBounds().x;
}
@Override
public int getY() {
return shape.getBounds().y;
}
@Override
public void mouseClicked(MouseEvent me) {
}
@Override
public void mouseEntered(MouseEvent me) {
}
@Override
public void mouseExited(MouseEvent me) {
}
@Override
public void mousePressed(MouseEvent me) {
model.setArmed(true);
model.setPressed(true);
paintImmediately();
}
@Override
public void mouseReleased(MouseEvent me) {
model.setArmed(false);
model.setPressed(false);
paintImmediately();
}
@Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Paint oldPaint = g2.getPaint();
Stroke oldStroke = g2.getStroke();
Font oldFont = g2.getFont();
AffineTransform oldTrans = g2.getTransform();
FontMetrics fm = g2.getFontMetrics(getFont());
Rectangle2D tb = fm.getStringBounds(getText(), g2);
AffineTransform t = new AffineTransform();
t.setToTranslation(-1 * shape.getBounds().getX(), -1 * shape.getBounds().getY());
t.concatenate(oldTrans);
g2.setTransform(t);
if (getModel().isArmed() || getModel().isPressed())
g2.setPaint(Color.RED);
else
g2.setPaint(Color.GREEN);
g2.fill(shape);
g2.setStroke(new BasicStroke(4));
g2.setPaint(Color.WHITE);
g2.draw(shape);
g2.setPaint(Color.BLACK);
g2.setFont(getFont());
g2.drawString(getText(), (int) (xText + 2 - tb.getWidth() / 2),
(int) (yText + 2 + fm.getAscent() * 0.35));
g2.setPaint(Color.WHITE);
g2.drawString(getText(), (int) (xText - tb.getWidth() / 2), (int) (yText + fm.getAscent() * 0.35));
g2.setFont(oldFont);
g2.setStroke(oldStroke);
g2.setPaint(oldPaint);
}
protected void calcShape() {
Arc2D a = new Arc2D.Double(xOffset, yOffset, 2 * rOuter, 2 * rOuter, angStart, angSize,
Arc2D.PIE);
Ellipse2D e = new Ellipse2D.Double(xOffset + rOuter - rInner, yOffset + rOuter - rInner,
2 * rInner, 2 * rInner);
Area resShape = new Area(a);
resShape.subtract(new Area(e));
this.shape = resShape;
}
protected void calcText() {
double angle = angStart + angSize / 2;
double r = rInner + (rOuter - rInner) / 2;
double xOff = r * Math.sin(Math.toRadians(90 + angle));
double yOff = r * Math.cos(Math.toRadians(90 + angle));
xText = xCenter + (Math.abs(xOff) > 0.1 ? xOff : 0);
yText = yCenter + (Math.abs(yOff) > 0.1 ? yOff : 0);
}
protected void paintImmediately() {
Component c = SwingUtilities.getRoot(this);
Graphics g = c.getGraphics();
Graphics2D g2 = (Graphics2D) g;
Point p = SwingUtilities.convertPoint(this, new Point(0, 0), c);
AffineTransform oT = g2.getTransform();
AffineTransform t = new AffineTransform();
t.setToTranslation(p.getX(), p.getY());
g2.setTransform(t);
paintComponent(g);
g2.setTransform(oT);
}
private double xCenter;
private double yCenter;
private double xOffset;
private double yOffset;
private double rOuter;
private double rInner;
private double angStart;
private double angSize;
private double xText;
private double yText;
private Shape shape;
}
, а теперь класс Pane:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestCirclePane extends JPanel {
public TestCirclePane(int w, int h) {
diameter = (int) (0.9 * (w < h ? w : h));
Dimension s = new Dimension(w, h);
xCenter = w / 2;
yCenter = h / 2;
setMinimumSize(s);
setPreferredSize(s);
setLayout(null);
createComponents(this);
}
protected void createComponents(JPanel p) {
double r = diameter / 2;
double w = r * 0.66;
double r3o = r;
double r3i = r - w * 0.5;
add(new MyCircleButton("B0", xCenter, yCenter, r3o, r3i, 135, 90));
add(new MyCircleButton("B1", xCenter, yCenter, r3o, r3i, 45, 90));
add(new MyCircleButton("B2", xCenter, yCenter, r3o, r3i, -45, 90));
add(new MyCircleButton("B3", xCenter, yCenter, r3o, r3i, 225, 90));
}
@Override
protected void paintComponent(Graphics arg0) {
super.paintComponent(arg0);
Graphics2D g2 = (Graphics2D) arg0;
Dimension d = getSize();
Paint oldPaint = g2.getPaint();
g2.setPaint(Color.WHITE);
g2.fill3DRect(0, 0, d.width, d.height, true);
g2.setPaint(Color.LIGHT_GRAY);
g2.drawLine(0, yCenter, d.width, yCenter);
g2.drawLine(xCenter, 0, xCenter, d.height);
g2.setPaint(oldPaint);
}
public static void createWindow() {
JFrame frame = new JFrame("Test - CircleButton");
JPanel client = new JPanel();
client.setLayout(new BorderLayout());
client.add(placeHolder("top"), BorderLayout.NORTH);
client.add(placeHolder("bottom"), BorderLayout.SOUTH);
client.add(placeHolder("left"), BorderLayout.WEST);
client.add(placeHolder("right"), BorderLayout.EAST);
client.add(new TestCirclePane(800, 600), BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(client);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
createWindow();
}
});
}
public static JComponent placeHolder(String s) {
JLabel l = new JLabel(s);
l.setPreferredSize(new Dimension(300, 300));
return l;
}
private int xCenter;
private int yCenter;
private int diameter;
private static final long serialVersionUID = 1L;
}
Поскольку кнопка с этой формой не ведет себя как «обычная» кнопка, мне нужно было добавить слушателя мыши. Для визуальной обратной связи по клику я использовал mousePressed()
и mouseReleased()
. Но когда мой paintComponent()
был вызван из-за пределов цепочки краски, я понял, что он не знает своего происхождения (кнопок).
Поэтому я подумал, что внутри моей краски сразу же находится за пределами концепции рисования кнопок , Поэтому я подготовил среду, как суперкласс будет делать при обычных операциях рисования. Ну, то, что я думал, суперкласс сделает. Не знаю - просто предположение.
Так что, если вы думаете, что мое кодирование неверно, пожалуйста, объясните мне, как сделать лучше.