Warum berücksichtigt die Zeichenmethode der Grafik keine Strichattribute?
Frage
Ich möchte einen benutzerdefinierten Rahmen mit abgerundeten Ecken erstellen.
Code -
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.RenderingHints;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.border.AbstractBorder;
class JRoundedCornerBorder extends AbstractBorder
{
private static final long serialVersionUID = 7644739936531926341L;
private static final int THICKNESS = 5;
JRoundedCornerBorder()
{
super();
}
@Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height)
{
Graphics2D g2 = (Graphics2D)g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if(c.hasFocus())
{
g2.setColor(Color.BLUE);
}
else
{
g2.setColor(Color.BLACK);
}
g2.setStroke(new BasicStroke(THICKNESS, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g2.drawRect(x, y, width - 1, height - 1);
g2.dispose();
}
@Override
public Insets getBorderInsets(Component c)
{
return new Insets(THICKNESS, THICKNESS, THICKNESS, THICKNESS);
}
@Override
public Insets getBorderInsets(Component c, Insets insets)
{
insets.left = insets.top = insets.right = insets.bottom = THICKNESS;
return insets;
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
// Add button with custom border
final JButton button = new JButton("Hello");
button.setBorder(new JRoundedCornerBorder());
frame.add(button);
// Add button without custom border
frame.add(new JButton("Goodbye"));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
Ergebnis -
Wie Sie sehen können, ignoriert Graphics.drawRect
die Attribute BasicStroke.CAP_ROUND
und BasicStroke.JOIN_ROUND
vollständig.Warum?
Lösung
Wie unter Lernen von Java 2D, Teil 1 erläutert :
java.awt.BasicStroke.CAP_ROUND
: Hiermit wird eine kreisförmige Kappe auf dem Endpunkt mit einem Durchmesser der Stiftbreite zentriert.Das Schlüsselwort ist "zentriert". Ich glaube, dass Java2D beim Zeichnen mit dicken Strichen immer die Dicke der Linie entlang der hypothetischen, unendlich dünnen Linie zwischen den Mittelpunkten der Pixel an den Start- und Endkoordinaten zentriert. Wenn Sie beispielsweise eine vertikale blaue Linie mit einer Dicke von 7 Pixel zeichnen, malt Java2D 3 Pixel auf jeder Seite des hypothetischen Liniensegments, das gezeichnet wird.
In Ihrem Beispiel beträgt die Dicke 5 Pixel. Sie müssen die Koordinaten versetzen, um den Strich vollständig innerhalb des Grafikclips zu zeichnen. Durch Verschieben in 2 Pixel (oder
THICKNESS/2
) werden die abgerundeten Ecken sichtbar:
//... g2.setStroke(new BasicStroke(THICKNESS, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.drawRect(x + THICKNESS/2, y + THICKNESS/2, width - 2*(THICKNESS/2) - 1, height - 2*(THICKNESS/2) - 1); g2.dispose(); } @Override public Insets getBorderInsets(Component c) { return new Insets(THICKNESS + THICKNESS/2, THICKNESS + THICKNESS/2, THICKNESS + THICKNESS/2, THICKNESS + THICKNESS/2); } //...
Andere Tipps
Das Problem ist der Versatz: Sie schneiden den Rand in der Mitte effektiv ab, sodass die Ecken nicht abgerundet erscheinen.Berücksichtigen Sie dies (hier nur für den Versatz, müssen Sie auch die Breite anpassen)
g2.drawRect(x + thickness/2, y + thickness/2,
width - 1 - thickness, height - 1 - thickness);
Bearbeiten
Feste schlampige Pixelzählung :-)