Ce tutoriel explique comment surcharger la méthode paintComponent des objets graphiques Swing afin de pouvoir modifier leur aspect. Les codes donnés en exemple sont disponible à cette adresse : http://codes-sources.commentcamarche.net/source/51830-personaliser-les-composants-swing
Le code de darksidious utilisé pour la partie 4 se trouve à cette adresse : http://codes-sources.commentcamarche.net/source/42967-button-graphique-effet-glass
La personnalisation des composants se fait toujours de la même manière, en surchargeant les méthodes paintCompoent du composant à personnaliser. Nous allons voire comment insérer un dégradé de couleur, une image sur des boutons ou des JPanel. Ces deux composants nous permettrons d'aborder les principales difficultés rencontrées. Il sera donc facile de personnaliser d'autres composants une fois que nous saurons comment personnaliser ces composants.
La méthode paintComponent permet de dessiner un objet graphique. Cette méthode est définie pour tous les composants Swing et nous l'appelons sans le savoir quand nous faisons un repaint(). Elle prend un attribut Graphics. C'est l'élément sur lequel nous allons dessiner.
Surcharger une méthode signifie redéfinir la méthode pour une classe héritière, voici la base de la surcharge de la méthode paintComponent pour un Jpanel :
public class PanelPerso extends JPanel { public PanelPerso(){ super(); } protected void paintComponent(Graphics g){ } }
Pour dessiner le composant il suffit donc de remplir la méthode paintComponent. Les paragraphes suivants nous donnent les bases pour dessiner.
L'origine du repère est situé en haut à gauche du composant, l'axe des abscisses est orienté de gauche à droite et l'axe des ordonnées de haut en bas.
Pour connaître les dimensions du composant, nous allons utiliser les méthodes getWidth() pour la largeur et getHeigth() pour la hauteur.
protected void paintComponent(Graphics g){ /* La diagonale va de l'origine au point bas gauche * donc du point (0, 0) au point (getWidth(), getHeigth()) */ g.drawLine(0, 0, getWidth(), getHeight()); }
Ovale : g.drawOval(x, y, width, height);
Arc de cercle : g.drawArc(x, y, width, height, startAngle, arcAngle);
Rectangle : g.drawRect(x, y, width, height);
Rectangle arrondi : g.drawRoundRect(x, y, width, height, arcWidth, arcHeight);
Chaîne de caractères : g.drawString("chaine", x, y);
Les méthodes préfixées par draw ne dessinent que les contours, pour remplir le dessin, on utilise les mêmes méthodes préfixées par fill.
Pour dessiner en couleurs, il suffit de faire un setColor sur l'élément graphique. Par exemple, pour dessiner les deux diagonales d'un JPanel de couleurs différentes le tout sur un rectangle blanc :
protected void paintComponent(Graphics g){ g.setColor(Color.white); g.fillRect(0, 0, getWidth(), getHeight()); g.setColor(Color.cyan); g.drawLine(0, 0, getWidth(), getHeight()); g.setColor(Color.red); g.drawLine(getWidth(), 0, 0, getHeight()); }
public void paintComponent(Graphics g) { try { BufferedImage image = ImageIO.read(new File(adresseImage)); g.drawImage(image, 0, 0, null); } catch (IOException e) { e.printStackTrace(); } }
Lorsqu'on surcharge les paintComponent des composants tels que JLabel et JButton, il faut redéfinit l'écriture du texte et centrer le texte.
Les lignes suivantes permettent de récupérer les coordonnées qui vont centrer le texte « Texte »
FontMetrics fm = g.getFontMetrics(); int x = (this.getWidth() - fm.stringWidth("Texte")) / 2; int y = (fm.getAscent() + (this.getHeight() - (fm.getAscent() + fm.getDescent())) / 2);
Code de la fonction paintComponent permettant de créer un bouton avec un texte et un rectangle centrés:
public void paintComponent(Graphics g){ g.setColor(Color.orange); g.fillRect(getWidth()/2 - getWidth()/8, getHeight()/2 - getHeight()/8, getWidth()/4, getHeight()/4); g.setColor(Color.black); FontMetrics fm = g.getFontMetrics(); int x = (this.getWidth() - fm.stringWidth(this.name)) / 2; int y = (fm.getAscent() + (this.getHeight() - (fm.getAscent() + fm.getDescent())) / 2); g.drawString(this.name, x, y); }
Vous savez à présent personnaliser vos composants de manière assez basique, nous allons voire comment obtenir des composants de meilleure qualité avec des gradients.
Les gradients sont des dégradés de couleurs, ils peuvent contenir autant de couleurs que vous voulez, nous nous limiterons à deux, il sera cependant facile d'en faire de même avec trois couleurs ou plus.
Le gradient est constitué de deux couleurs que nous appellerons couleur1 et couleur2. Pour le définir, nous avons également besoin de savoir à quel endroit la couleur du gradient sera exactement la couleur définie. Nous allons donc utiliser le tableau dist.
Color[] colors = {couleur1, couleur2}; float[] dist = {0.0f, 1.0f}; /* Ce qui signifie qu'au point de départ du gradient (0.0f), * le gradient à la couleur couleur 1 */ new LinearGradientPaint( new Point2D.Float(0, 0), new Point2D.Float(0, hauteur), dist, colors);
Le problème du gradient pour la surcharge de la méthode paintComponent est que ce n'est pas un objet graphics mais graphics 2D. Nous devons donc caster g en Graphics2D.
Graphics2D g2d; if (g instanceof Graphics2D) { g2d = (Graphics2D) g; } else { System.out.println("Error"); return; }
Code complet de la méthode
protected void paintComponent(Graphics g){ Paint paint; Graphics2D g2d; if (g instanceof Graphics2D) { g2d = (Graphics2D) g; } else { System.out.println("Error"); return; } Color[] colors = {couleur1, couleur2}; float[] dist = {0.0f, 1.0f}; paint = new LinearGradientPaint( new Point2D.Float(0, 0), new Point2D.Float(0, getHeight()), dist, colors); g2d.setPaint(paint); g2d.fillRect(0, 0, getWidth(), getHeight()); }
Cette partie s'inspire d'un code posté par Darksidious à l'adresse suivante : http://codes-sources.commentcamarche.net/source/42967-button-graphique-effet-glass
Cette classe permet de créer un bouton assez sympa, testez le et vous verrez...
public class BoutonRond extends JButton { private static final long serialVersionUID = 1L; private final int BULLE_WIDTH; private Color BULLE_COLOR; private Color BULLE_COLOR_D; private Color BULLE_COLOR_B; private Color currentColor; private Color couleurTexte; private Font font; private String texte="null"; private int x = 4; private int y = 4; public BoutonRond(Color couleur, int taille) { BULLE_COLOR=couleur; BULLE_COLOR_D=couleur.darker(); BULLE_COLOR_B=couleur.brighter(); currentColor=BULLE_COLOR_D; BULLE_WIDTH=taille; initialize(); } public BoutonRond(Color couleur, int taille, String texte, Font f, Color couleurTexte) { BULLE_COLOR=couleur; BULLE_COLOR_D=couleur.darker(); BULLE_COLOR_B=couleur.brighter(); currentColor=BULLE_COLOR; BULLE_WIDTH=taille; this.font=f; this.texte=texte; this.couleurTexte=couleurTexte; initialize(); } public void setColor(Color c){ this.BULLE_COLOR_D=c; } private void initialize() { this.setFocusPainted(false); this.setSize(new Dimension(BULLE_WIDTH + 10, BULLE_WIDTH + 10)); this.setBorderPainted(false); this.setContentAreaFilled(false); this.setOpaque(false); this.addMouseListener(new java.awt.event.MouseListener() { public void mouseEntered(java.awt.event.MouseEvent e) { if (isEnabled()) { // on change la couleur currentColor = BULLE_COLOR_B; } } public void mouseClicked(java.awt.event.MouseEvent e) { } public void mousePressed(java.awt.event.MouseEvent e) { x-=2; y-=2; } public void mouseReleased(java.awt.event.MouseEvent e) { x+=2; y+=2; } public void mouseExited(java.awt.event.MouseEvent e) { if (isEnabled()) { // on rétablit la couleur d'origine // System.out.println("couleur d'origine"); currentColor = BULLE_COLOR_D; } } }); } public void paint(Graphics arg0) { super.paint(arg0); Graphics2D g2d = (Graphics2D) arg0; g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setColor(currentColor); g2d.setStroke(new BasicStroke(3)); g2d.drawOval(x, y, BULLE_WIDTH, BULLE_WIDTH); GradientPaint gradient = new GradientPaint(BULLE_WIDTH / 2, y, currentColor, (BULLE_WIDTH) / 2, y + BULLE_WIDTH, Color.white); g2d.setPaint(gradient); g2d.fillOval(x, y, BULLE_WIDTH, BULLE_WIDTH); gradient = new GradientPaint(BULLE_WIDTH / 2, y, Color.white, BULLE_WIDTH / 2, y + BULLE_WIDTH / 2, new Color(currentColor getRed(), currentColor.getGreen(), currentColor getBlue(), 0)); g2d.setPaint(gradient); g2d.fillOval(x + BULLE_WIDTH / 5, y, 5 * BULLE_WIDTH / 8, BULLE_WIDTH / 3); if(this.texte!="null"){ g2d.setFont(this.font); float[] dist = {0.1f, 0.3f}; Color c = new Color(22,22,22,0); Color[] colors = {c, this.couleurTexte}; Paint gp = new LinearGradientPaint(new Point2D.Float(0, 0), new Point2D.Float(0, getHeight()), dist, colors); g2d.setPaint(gp); FontMetrics fm = g2d.getFontMetrics(); int x0 = (this.getWidth() - fm.stringWidth(this.texte)) / 2; int y0 = (fm.getAscent() + (this.getHeight() - (fm.getAscent() + fm.getDescent())) / 2); g2d.drawString(this.texte, x0, y0); } } }