lunes, 25 de abril de 2011

Programa simple de dibujo con swing. Pintar en un lienzo usando MouseListener y MouseMotionListener

1 comentarios
Hola de nuevo.

Hoy vamos a empezar a captar los eventos de ratón y a utilizarlos para crear un programa simple de dibujo. Básicamente añadiremos unos listeners a un JFrame para lograr captar los eventos de ratón y así identificar los puntos por los que desplazamos el puntero.

Estos MouseAdapter y MouseMotionAdapter implementan las interfaces MouseListener y MouseMotionListener respectivamente, que se encargan de detectar eventos de ratón, como clicks, entradas y salidas del puntero en determinadas zonas, desplazamientos y arrastres de ratón.

En el ejemplo de hoy utilizaremos estos eventos para dibujar puntos sobre un lienzo, os dejo el código a continuación. Y ya sabéis, cualquier duda dejar un comentario y os responderé con la mayor brevedad posible.


import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;

import javax.swing.JFrame;
import javax.swing.JLabel;

public class Painter extends JFrame {

 private int cuentaPuntos = 0;

 private JLabel j = new JLabel();

 // arreglo de referencias a java.awt.Point
 private int maxPoints = 1500;
 private Point puntos[] = new Point[maxPoints];

 // configurar GUI y registrar manejador de eventos de ratón
 public Painter() {
  super("Un programa simple de dibujo");

  // crear una etiqueta y colocarla en la parte SOUTH del esquema
  // BorderLayout

  getContentPane().add(new JLabel("Arrastre el ratón para dibujar"), BorderLayout.SOUTH);
  getContentPane().add(j, BorderLayout.NORTH);

  // Ahora añadimos listeners propios para los eventos de ratón
  addMouseMotionListener(

  new MouseMotionAdapter() { // clase interna anónima

   // almacenar coordenadas de arrastre de ratón y llamar a repaint
   @Override
   public void mouseDragged(MouseEvent evento) {
    if (cuentaPuntos < puntos.length) {
     puntos[cuentaPuntos] = evento.getPoint();
     ++cuentaPuntos;
     repaint();
     j.setText("Van: " + cuentaPuntos + " puntos, le quedan: " + (maxPoints - cuentaPuntos) + " puntos");
    }
   }

  } // fin de la clase interna anónima

  ); // fin de la llamada a addMouseMotionListener

  addMouseListener(

  new MouseAdapter() { // clase interna anónima

   // almacenar coordenadas de click de ratón
   @Override
   public void mouseClicked(MouseEvent evento) {
    if (cuentaPuntos < puntos.length) {
     puntos[cuentaPuntos] = evento.getPoint();
     ++cuentaPuntos;
     repaint();
     j.setText("Van: " + cuentaPuntos + " puntos, le quedan: " + (maxPoints - cuentaPuntos) + " puntos");
    }
   }

  } // fin de la clase interna anónima

  ); // fin de la llamada a addMouseListener

  setSize(400, 200);
  setVisible(true);

 } // fin del constructor de Pintor

 // dibujar óvalo en un cuadro delimitador de 2 por 2 en ubicación
 // especificada en ventana
 @Override
 public void paint(Graphics g) {
  super.paint(g); // borra el área de dibujo

  for (int i = 0; i < puntos.length && puntos[i] != null; i++)
   g.fillOval(puntos[i].x, puntos[i].y, 2, 2);
 }

 public static void main(String args[]) {
  Painter aplicacion = new Painter();
  aplicacion.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 }

}


Espero que os sea útil :)

lunes, 11 de abril de 2011

Botones bordes redondos y con forma, personalizar los JButton

2 comentarios
Decíamos que una de las características de Swing es su facilidad para personalizar nuestros componentes mediante la modificación de su ComponentUI. Hoy vamos a ver como darle un aspecto personalizado a nuestros botones.

Aquí os dejaré unas líneas generales de como hacerlo, pero el límite lo ponéis vosotros y vuestra imaginación. Crearemos una subclase de BasicButtonUI y sobrescribiremos su método paint() para darle un aspecto determinado a nuestros botones y así conseguir este aspecto:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.RoundRectangle2D;

import javax.swing.AbstractButton;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.plaf.basic.BasicButtonUI;

public class ShapedButton {

 private static JFrame frame;

 public Component createComponents() {

  // Tres botones para probar diferentes efectos
  JButton roundButton = new JButton("Redondo");
  JButton squareButton = new JButton("Cuadrado");
  JButton polygonButton = new JButton("Poligonal");

  // Establecemos un UI específico
  ShapedButtonUI roundUI = new ShapedButtonUI();
  roundUI.setShape(ButtonShape.ROUND, roundButton);
  roundButton.setUI(roundUI);
  roundButton.setPreferredSize(new Dimension(100, 100));
  ShapedButtonUI squareUI = new ShapedButtonUI();
  squareUI.setShape(ButtonShape.SQUARE, squareButton);
  squareButton.setUI(squareUI);
  squareButton.setPreferredSize(new Dimension(100, 100));
  ShapedButtonUI polygonUI = new ShapedButtonUI();
  polygonUI.setShape(ButtonShape.POLYGON, polygonButton);
  polygonButton.setUI(polygonUI);
  polygonButton.setPreferredSize(new Dimension(100, 100));

  // Añadimos nuestros componentes
  JPanel panel = new JPanel();
  panel.add(roundButton);
  panel.add(squareButton);
  panel.add(polygonButton);

  return panel;
 }

 /**
  * Definimos tres posibles formas para los botones
  */
 public enum ButtonShape {
  ROUND,
  SQUARE,
  POLYGON
 }

 private class ShapedButtonUI extends BasicButtonUI {

  /** Button shape. */
  private ButtonShape shape;

  public ShapedButtonUI() {
   super();
  }

  public void setShape(ButtonShape shape, JButton button){
   // no pintamos el borde
   button.setBorderPainted(false);
   this.shape = shape;
  }

  @Override
  public void paint(Graphics g, JComponent c) {

   Graphics2D g2d = (Graphics2D) g;

   // definamos las formas de nuestros botones
   Shape buttonShape = null;
   switch (shape) {
    case ROUND:
     buttonShape = new RoundRectangle2D.Double(0, 0, c.getWidth() - 1, c.getHeight() - 1, 50, 50);
     break;
    case SQUARE:
     buttonShape = new Rectangle(0, 0, c.getWidth(), c.getHeight());
     break;
    case POLYGON:
     int[] xPoints = {0, 0 + c.getWidth() / 3, 0 + 2 * (c.getWidth() / 3), c.getWidth(), 0 + 2 * (c.getWidth() / 3), 0 + c.getWidth() / 3};
     int[] yPoints = {c.getHeight() / 2, 0, 0, c.getHeight() / 2, c.getHeight(), c.getHeight()};
     buttonShape = new Polygon(xPoints, yPoints, 6);
     break;
   }

   // establecemos un gradiente para el fondo del boton
   GradientPaint gp = new GradientPaint(0, 0, Color.GREEN, c.getWidth(), c.getHeight(), Color.BLUE);
   g2d.setPaint(gp);
   g2d.fill(buttonShape);

   super.paint(g2d, c);

  }

  @Override
  protected void paintButtonPressed(Graphics g, AbstractButton b) {
   Graphics2D g2d = (Graphics2D) g;

   // definamos las formas de nuestros botones
   Shape buttonShape = null;
   switch (shape) {
    case ROUND:
     buttonShape = new RoundRectangle2D.Double(0, 0, b.getWidth() - 1, b.getHeight() - 1, 50, 50);
     break;
    case SQUARE:
     buttonShape = new Rectangle(0, 0, b.getWidth(), b.getHeight());
     break;
    case POLYGON:
     int[] xPoints = {0, 0 + b.getWidth() / 3, 0 + 2 * (b.getWidth() / 3), b.getWidth(), 0 + 2 * (b.getWidth() / 3), 0 + b.getWidth() / 3};
     int[] yPoints = {b.getHeight() / 2, 0, 0, b.getHeight() / 2, b.getHeight(), b.getHeight()};
     buttonShape = new Polygon(xPoints, yPoints, 6);
     break;
   }

   // establecemos un gradiente para el fondo del boton
   GradientPaint gp = new GradientPaint(0, 0, Color.BLUE, 0, b.getHeight(), Color.GREEN);
   g2d.setPaint(gp);
   g2d.fill(buttonShape);
  }
 }

 /**
  * 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("Shaped button");
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

  ShapedButton app = new ShapedButton();
  Component contents = app.createComponents();
  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();
   }
  });
 }

viernes, 8 de abril de 2011

El Look and Feel (L&F) de Swing, cambiar el look and feel de la aplicación

3 comentarios
Tal y como está diseñado Swing, puedes cambiar el "look and feel" (L&F) de nuestras interfaces. "Look" se refiere a la apariencia de los componentes, "feel" se refiere a la manera en que se comportan estos.


Cada componente Swing se divide en dos clases distintas, una subclase de JComponent y otra subclase de ComponentUI. Por ejemplo un JButton tiene una implementación concreta de ButtonUI.


Veamos ahora varios ejemplos de como cambiar el look and feel de nuestra aplicación:


Programáticamente

 Para especificarlo haremos uso del método UIManager.setLookAndFeel() con el nombre completo de una subclase de LookAndFeel y los argumentos apropiados. P ej.
public static void main(String[] args) {
try {
// Establecemos el look and feel "Metal"
UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
} 
catch (UnsupportedLookAndFeelException e) {
// manejar excepción
}
catch (ClassNotFoundException e) {
// manejar excepción
}
catch (InstantiationException e) {
// manejar excepción
}
catch (IllegalAccessException e) {
// manejar excepción
}

new SwingApplication(); //Creamos y mostramos la interfaz de usuario
}

Por línea de comandos

Podemos especificar el L&F por línea de comandos usando el flag -D para establecer la propiedad swing.defaultlaf: P ej.

java -Dswing.defaultlaf=com.sun.java.swing.plaf.windows.WindowsLookAndFeel MyApp

Archivo swing.properties

Otra manera es cambiar el swing.properties, es posible que tengamos que crear este archivo. Suele estar ubicado en la carpeta lib de nuestro intérprete de Java.

# Swing properties
swing.defaultlaf=com.sun.java.swing.plaf.windows.WindowsLookAndFeel

Despues del inicio de la aplicación

Se puede cambiar el aspecto de la aplicación incluso despues de haber hecho visible la ventana. Para ahcer efectivo el cambio, deberemos llamar al método updateComponentTreeUI de SwingUtilities por cada contenedor de alto nivel. P ej.

UIManager.setLookAndFeel(lnfName);
SwingUtilities.updateComponentTreeUI(frame);
frame.pack();

Para hacer esto algo más gráfico aquí os dejo el código de una aplicación de ejemplo para cambiar el Look and Feel tras iniciar la aplicación.

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class LookAndFeelDemo {

 static JFrame frame;
 JLabel label;
 JComboBox combo;

 public Component createComponents() {

  label = new JLabel("Selecciona un L&F");
  combo = new JComboBox();

  // Añado elementos al combo
  combo.addItem("Metal");
  combo.addItem("Nimbus");
  combo.addItem("Windows");
  combo.addItem("Motif");

  combo.addActionListener(new ActionListener() {

   @Override
   public void actionPerformed(ActionEvent e) {
    initLookAndFeel(combo.getSelectedItem().toString());
   }
  });

  label.setLabelFor(combo);

  JPanel pane = new JPanel(new GridLayout(0, 1));
  pane.add(label);
  pane.add(combo);
  pane.setBorder(BorderFactory.createEmptyBorder(30, // top
  30, // left
  10, // bottom
  30) // right
  );

  return pane;
 }

 private static void initLookAndFeel(String LaF) {
  String lookAndFeel = null;

  if (LaF != null) {
   if (LaF.equals("Metal")) {
    lookAndFeel = "javax.swing.plaf.metal.MetalLookAndFeel";
   } else if (LaF.equals("Nimbus")) {
    lookAndFeel = "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel";
   } else if (LaF.equals("Windows")) {
    lookAndFeel = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
   } else if (LaF.equals("Motif")) {
    lookAndFeel = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
   } else {
    lookAndFeel = UIManager.getCrossPlatformLookAndFeelClassName();
   }

   try {
    UIManager.setLookAndFeel(lookAndFeel);
    SwingUtilities.updateComponentTreeUI(frame);
    frame.pack();
   } catch (ClassNotFoundException e) {
    e.printStackTrace();
   } catch (UnsupportedLookAndFeelException e) {
    e.printStackTrace();
   } catch (Exception e) {
    e.printStackTrace();
   }
  }
 }

 /**
  * Create the GUI and show it. For thread safety,
  * this method should be invoked from the
  * event dispatch thread.
  */
 private static void createAndShowGUI() {
  // Make sure we have nice window decorations.
  JFrame.setDefaultLookAndFeelDecorated(true);

  // Create and set up the window.
  frame = new JFrame("Look And Feel Demo");
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

  LookAndFeelDemo app = new LookAndFeelDemo();
  Component contents = app.createComponents();
  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();
   }
  });
 }
}

lunes, 4 de abril de 2011

¿Qué es Java Swing?

4 comentarios
Empecemos por el principio, ¿que es java swing?
Pues bien, el paquete javax.swing nos proporciona una serie de componentes "ligeros" (todo en lenguaje Java) que, al máximo grado posible funcionan igual en todas las plataformas.
Swing nos permite dotar de una interfaz gráfica de usuario a nuestras aplicaciones, dotándolas de interactividad y riqueza visual.


Veamos nuestro primer ejemplo de esta tecnología al alcance de todos. Para empezar os dejo con el típico ejemplo del "Hola Mundo" hecho con Swing. Copiar, pegar y ejecutar para ver el resultado...





import javax.swing.JFrame;
import javax.swing.JLabel;

public class HolaMundoSwing extends JFrame {

 private static void createAndShowGUI() {
  // Crea y prepara la ventana.
  JFrame frame = new JFrame(&quot;HolaMundoSwing&quot;);
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

  // A&Atilde;&plusmn;ade la etiqueta &quot;Hola Mundo&quot;.
  JLabel label = new JLabel(&quot;Hola Mundo en Swing&quot;);
  frame.getContentPane().add(label);

  // Mostramos la ventana.
  frame.setSize(300, 100);
  frame.setVisible(true);
 }

 public static void main(String[] args) {
  // Programa un trabajo para el hilo de despacho de eventos:
  // creando y mostrando la ventana de la aplicaci&Atilde;&sup3;n.
  javax.swing.SwingUtilities.invokeLater(new Runnable() {
   public void run() {
    createAndShowGUI();
   }
  });

 }
}