lunes, 9 de mayo de 2011

Bordes redondeados, creando nuestro propio borde para los componentes

1 comentarios
Hola de nuevo,

Hoy vamos a profundizar un poco en el tema de los elementos Border de los componentes Swing.

Todo componente al dibujarse lo hace en 2 partes, el contenido y su borde, así que hoy vamos a ver como personalizar un poco mas cualquiera de nuestros componentes añadiéndole un borde definido por nosotros mismos.

Aquí os dejo la clase de nuestro borde, con los métodos mínimos que toda clase que herede de AbstractBorder debería implementar. Esta es la clase de la que parten todos los bordes utilizados en Swing.
Ya sabéis que siempre pretendo dejaros un código auto-explicativo, pero para cualquier duda ya sabéis, dejadme un comentario y os contestaré en cuanto pueda.

package ejemplo5;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.geom.RoundRectangle2D;
import java.util.ArrayList;
import java.util.List;

import javax.swing.border.AbstractBorder;

/**
 * RoundedBorder.
 */
public class RoundedBorder extends AbstractBorder {

 private List<Color> colors;
 private int thickness;
 private int cornersArc;
 private int borders;

 /** Colores de los bordes. */
 private List<GradientPaint> gradients;
 /** Formas del bordes. */
 private List<RoundRectangle2D> rectangles;

 /**
  * @param color
  * @param thickness
  * @param roundedCorners
  */
 public RoundedBorder(List<Color> colors, int thickness, int cornersArc, int borders) {
  this.colors = colors;
  this.thickness = thickness;
  this.cornersArc = cornersArc;
  // Mínimo un borde
  this.borders = borders > 0 ? borders : 1;
 }

 @Override
 public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {

  createShapes(w, h, x, y);

  createGradients(c);

  Graphics2D g2d = ((Graphics2D) g);

  // Set a higher-quality rendering
  g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
  g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);

  for (int i = 0; i < borders; i++) {
   g2d.setPaint(gradients.get(i));

   g2d.setStroke(new BasicStroke(thickness));

   RoundRectangle2D auxRect = rectangles.get(i);
   g2d.drawRoundRect((int) auxRect.getX(), (int) auxRect.getY(), (int) auxRect.getWidth(), (int) auxRect.getHeight(), (int) auxRect.getArcWidth(), (int) auxRect.getArcHeight());
  }

 }

 /**
  * Creamos los gradientes.
  *
  * @param c Component
  */
 private void createGradients(Component c) {

  gradients = new ArrayList<GradientPaint>();
  for (int i = 0; i < borders; i++) {
   Color color = colors.get(i);
   GradientPaint gra = new GradientPaint(0, 0, color.darker(),
     0, c.getHeight(), color.brighter(), false);
   gradients.add(gra);
  }
 }

 /**
  * Creamos las formas del borde
  *
  * @param w ancho
  * @param h alto
  * @param x coordenada X
  * @param y coordenada Y
  */
 public void createShapes(int w, int h, int x, int y) {

  rectangles = new ArrayList<RoundRectangle2D>();
  int rectangleWidth = w, rectangleHeight = h;
  int xCoord = x;
  int yCoord = y;

  for (int i = 0; i < borders; i++) {
   if (i == 0) {
    xCoord += thickness / 2;
    yCoord += thickness / 2;
    rectangleWidth -= thickness;
    rectangleHeight -= thickness;
   } else {
    xCoord += thickness;
    yCoord += thickness;
    rectangleWidth -= 2 * thickness;
    rectangleHeight -= 2 * thickness;
   }

   RoundRectangle2D rectangle = new RoundRectangle2D.Float(xCoord, yCoord,
     rectangleWidth, rectangleHeight, cornersArc, cornersArc);

   rectangles.add(rectangle);

  }

 }

 /**
  * Este método nos dice cuanto espacio necesita el borde para dibujarse.
  */
 @Override
 public Insets getBorderInsets(Component c) {
  Insets insets = super.getBorderInsets(c);
  insets.left = insets.top = insets.right = insets.bottom += thickness * borders;
  return insets;
 }

}
Y aquí podéis ver un código de ejemplo que ilustrará el resultado obtenido:




package ejemplo5;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;

/**
 * Ejemplo5
 */
public class Ejemplo5 {

 private static JFrame frame;

 private static JPanel createExamplePanel() {
  JPanel panel = new JPanel();

  // Componentes de prueba
  JButton button = new JButton("Click");
  button.setPreferredSize(new Dimension(100, 100));
  button.setOpaque(false);
  JTextField textField = new JTextField(25);
  textField.setText("Escribe aqui...");
  textField.setOpaque(false);
  JTextArea textArea = new JTextArea(10, 25);
  textArea.setText("Escribe aqui...");
  textArea.setOpaque(false);

  List<Color> colors = new ArrayList<Color>();
  colors.add(Color.PINK);
  colors.add(Color.RED);

  button.setBorder(new RoundedBorder(colors, 5, 2, 2));

  colors = new ArrayList<Color>();
  colors.add(Color.PINK);
  colors.add(Color.RED);
  colors.add(Color.BLUE);
  colors.add(Color.YELLOW);

  textField.setBorder(new RoundedBorder(colors, 2,  5, 4));

  colors = new ArrayList<Color>();
  colors.add(Color.PINK);
  colors.add(Color.RED);
  colors.add(Color.BLUE);
  textArea.setBorder(new RoundedBorder(colors, 4, 5, 3));

  panel.add(button);
  panel.add(textField);
  panel.add(textArea);

  return panel;
 }

 /**
  * Create the GUI and show it. For thread safety,
  * this method should be invoked from the
  * event dispatch thread.
  */
 private static void createAndShowGUI() {

  // Create and set up the window.
  frame = new JFrame("RoundedBorder");
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

  Component contents = createExamplePanel();
  frame.getContentPane().add(contents, BorderLayout.CENTER);

  // Display the window.
  frame.pack();
  frame.setLocationByPlatform(true);
  frame.setVisible(true);
 }

 public static void main(String[] args) {
  // Schedule a job for the event dispatch thread:
  // creating and showing this application's GUI.
  javax.swing.SwingUtilities.invokeLater(new Runnable() {
   public void run() {
    createAndShowGUI();
   }
  });
 }

}

Un saludo y hasta pronto...