Pourquoi la méthode du dessin des graphiques ne respecte-t-elle pas les attributs de course?
Question
Je veux créer une bordure personnalisée avec des coins arrondis.
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);
}
});
}
}
Résultat -
Comme tu peux le voir, Graphics.drawRect
ignore complètement le BasicStroke.CAP_ROUND
et BasicStroke.JOIN_ROUND
les attributs. Pourquoi?
La solution
Comme expliqué à Apprendre Java 2d, partie 1:
java.awt.BasicStroke.CAP_ROUND
: Cela rend un capuchon circulaire centré sur le point d'extrémité, avec un diamètre de la largeur du stylo.
Le mot clé est "centré". Je crois que c'est toujours le cas que lors du dessin avec des traits épais, Java2d centrera l'épaisseur de la ligne le long de la ligne hypothétique et infiniment mince entre les centres des pixels aux coordonnées de départ et de fin. Par exemple, lors du dessin d'une ligne bleue verticale de 7 pixels d'épaisseur, Java2D peint 3 pixels de chaque côté du segment de ligne hypothétique qui est dessiné.
Dans votre exemple, l'épaisseur est de 5 pixels. Vous devez compenser les coordonnées pour dessiner complètement la course dans le clip graphique. En se déplaçant en 2 pixels (ou THICKNESS/2
), les coins arrondis deviennent visibles:
//...
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);
}
//...
Autres conseils
Le problème est le décalage: vous coupez efficacement la frontière au milieu afin que les coins ne semblent pas être arrondis. Le prendre en compte (ici uniquement pour le décalage, doit également régler la largeur)
g2.drawRect(x + thickness/2, y + thickness/2,
width - 1 - thickness, height - 1 - thickness);
Éditer
Compte de pixels bâclé fixes :-)