Mostrando las entradas con la etiqueta Java. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Java. Mostrar todas las entradas

jueves, mayo 10, 2012

MVC en Java - Model View Controller - Modelo Vista Controlador

Bueno, un tema complicado para escribir ya que se ha escrito demasiado, sobre algo que a mi parecer no tendría mucha relevancia, bueno sí, pero personalmente prefiero otras estructuras de organización de software. En fin, uno de mis amigos, me ha pedido que explique este Patrón de Diseño. Y que por su fama, y buen marketing  de software ha dado origen a otros patrones como el MVP (Model View Presenter)  y todos los model +view +something, Observer, etc. Además, este tópico, ha dado origen a las discusiones de café más apasionadas sobre los patrones de diseño de software y su utilidad real en el desarrollo actual.
Recuerdo haber leído algunos libros y ver representaciones del MVC, pero todos ellos mostraban en sus clases de la capa vista, una referencia a alguna clase de la capa modelo, o viceversa. Pero… y entonces…. tengo una duda; no era que el MVC era una “¿programación en 3 capas?”, y si hablamos de capas, por que existen referencias cruzadas.  Bueno, después de exhaustivos y apasionales debates sobre si el modelo debía considerarse una capa transversal a toda la arquitectura (y algunos otros argumentos más alocados), descubrimos, que el MVC  no fue igual toda la vida (es más hasta el día de hoy encuentro tantos MVC como arquitectos). Pero no todo es tan relativo, se mantiene algunos principios de responsabilidad de las capas.
Inicialmente y a grande rasgos, podemos decir que existen dos formas de MVC. Y la diferencia básica entre el primero y el segundo, es que en el primero (versión inicial), no se tiene una variable de referencia a alguna clase del “Modelo” en la capa de la vista, como mencione anteriormente.
Realizaré la presentacion en dos post, el primero, será el MVC inicial y el segundo el que tome en cuenta las relaciones entre el modelo, y la vista, y por que evoluciono de esta forma.

MVC + V1

La comunicación de cada capa con la inmediata superior, es lo que llevó a mucha gente a llamar a esto “programación en tres capas”. Como se distingue en las relaciones del diagrama, no existe una comunicación directa entre el modelo, y la vista.  Las referencias a interfaces y no directamente hacia las clases, nos permitirán un crecimiento por agregación (crear una clase y agregarla a nuestro software) y no por modificación. Así por ejemplo si en lugar de instanciar en el controlador un JFrame, instanciaramos un JInternalFrame, solo tendríamos que crear un Internal Frame e implementar la interfaz, sin tener que modificar el controlador mas que para cambiar la referencia.  En esta forma de orgenizar el código, solo se utilizan “objetos del lenguaje” (Map), y no "objetos del modelo" (Persona), y es esta característica, la que le dá la pureza de la separación entre capas.

El codigo fuente Java de esta Ejemplo se puede encontrar aquí!

Algunas consideraciones

Como vemos cada una de las clases tienen una referencia a una interfáz, y no a una clases concreta. También se lo puede hacer con clases abstractas, pero debido a la posibilidad de herencia múltiple de interfaces (Una interfaz puede heredar varias interfaces) e implementación múltiple que tienen las clases (Una clase puede implementar varias interfaces), en Java, nos conviene utilizarlo de esta forma para ganar en flexibilidad para agregar y sacar métodos

  ...
  private IControlable controler; 
  public FrmPersona(IControlable controler) {
    super();
    this.controler = controler;
    initGUI();
   }
  ... 
CtrlPersona.java
  ...
  private IDatable myView;
  private IActualizable myModel;
  ... 
Persona.java
  ...
  private IControlable controlador;
  public Persona(IControlable controlador){
 this.controlador = controlador;
  }
  ...

Vista - "Las pantallitas"1

La vista tiene como responsabilidad mostrar  y tomar datos. Las vistas no conocen nada de enteros, o tipos de dato. Todo para ellas son Strings. Con el desarrollo de las tecnologias web, se pensaba en poner validaciones de formato en esta capa (numerales, etc) para no tener que ir hasta los servidores y disminuir tanto performance como experiencia de usuario, pero con las tecnologias asincronas como ajax, esto pronto dejó de ser nacesario. No realiza ningún tipo de validación de negocio, ya que es el modelo el encargado de realizar dichas validaciones. Cada una de las acciones realizadas es una llamada al controlador para que él sea el encargado de tomar cualquier decisión.
  ...
  @Override
  public void setData(Map data) {
      this.txtNombre.setText(data.get(CtrlPersona.NAME));
      this.txtApellido.setText(data.get(CtrlPersona.SURNAME));
      this.txtEdad.setText(data.get(CtrlPersona.AGE));
  }
  ...
 @Override
 public Map getData() {
   Map data = new HashMap();
   data.put(CtrlPersona.NAME, this.txtNombre.getText());
   data.put(CtrlPersona.SURNAME, this.txtApellido.getText());
   data.put(CtrlPersona.AGE, this.txtEdad.getText());
   return data;
 }
 ...
 @Override
 public void actionPerformed(ActionEvent arg0) {
   if(arg0.getSource() == this.btnCancel){
     controler.cacelAction();
   }
   if(arg0.getSource() == this.btnOK){
     controler.oKAction();
   }
 }
 ...

Controlador - "Eso que entedes vos y nadie más... ponelo si querés...pero no pierdas tiempo.. bla bla...bla... cerveza!"1

En la capa de controlador, podemos encontrar que es donde se instancia las interfaces y modelos que el controlador quiere manejar. Una alternativa a esto ultimo, es que las instancias (Tanto de la vista, como del Modelo) sean pasadas como parametros al constructor del controlador.
Algunas de las responsabilidades de esta capa podrían ser las siguientes:
  • Realizar validaciones de formato
  • Subir y bajar variables de sesión
  • Redireccionar y hacer el forwared de las pantallas  y manejar el ciclo de vida de las Interfaces de usuario o sistemas.
  • Capturar tanto las excepciones de negocio, como de formato.
  • Tomar y poner información en las interfaces
  ...
  {
    myView = new FrmPersona(this);
    myModel = new Persona(this);
  }
  ...
  public void oKAction() {
    Map data = myView.getData();
    try{
        ParameterTool.checkMandatoryFields(data);
        ParameterTool.checkInteger(AGE, data.get(AGE));
        myModel.save(data);
    }catch(MenorDeEdadException e){
        setReturningMessage(e.getMessage());
    }catch(IllegalArgumentException e){
        setReturningMessage(e.getLocalizedMessage());
    }
  }
 ...

Modelo - "El diagramita de clases"1

La capa del modelo, es aquella que representa el negocio de la aplicación. Son aquellas clases con estructura de Java Beans que tanto conocemos. En un MVC la lógica de guardado de la base de datos suele estar en las clases del modelo, por supuesto haciendo llamadas a métodos de alguna librería o un paquete de utilidades para conectarnos con las bases. Es la capa que con las sucesivas iteraciones (y evoluciones a stacks de software) ha ido subdividiéndose, en subcapas, como por ejemplo la de repositorios de objetos.
Una responsabilidad de implementación definida e interesante de destacar es la de chequear las reglas del negocio.

Bueno, existe mucho más que se puede decir de este patrón, ya que como dije al principio, se ha hablado mucho. Pero esto es lo que considero importante para poder aplicarlo, no solo de una forma académica, si no también implementable.  En el próximo post escribiré de la evolución del MVC y esto será en los próximos N días.  (O tal vez  N a la M días).
Mi pasión siempre ha sido no solo hablar teóricamente de algo, porque de eso seguro hay mucha gente que puede hablar más y mejor, pero al final del día… siempre soy solo un programador… y quiero ¡ver pantallitas funcionando!

1) Nota: traducidos a lenguaje "jefe" para la fácil adaptacion a todo tipo de públicos.

martes, junio 08, 2010

UML: Diagrama de Clases, ejercicio 1

Acá les dejo un ejercicio que le preparé para un amigo. Por si lo quieren realizar. La respuesta la voy a postear en algunos días.

Ejercicio:


El objetivo, es realizar el código java del diagrama que figura a continuación. Los métodos, salvo aquellos de la agregación, pueden contener solo la firma, no hace falta la lógica.


Respuesta

by Charli Quiroga

Clase Vehículo



import java.util.List;

public abstract class Vehiculo implements Desplazable {

private double velocidadPromedio;
private int velocidadMaxima;
private List ruedas;
public Vehiculo() {
super();
}

public double getVelocidadPromedio() {
return velocidadPromedio;
}
public void setVelocidadPromedio(double velocidadPromedio) {
this.velocidadPromedio = velocidadPromedio;
}
public int getVelocidadMaxima() {
return velocidadMaxima;
}
public void setVelocidadMaxima(int velocidadMaxima) {
this.velocidadMaxima = velocidadMaxima;
}
public List getRuedas() {
return ruedas;
}
public void setRuedas(List ruedas) {
this.ruedas = ruedas;
}
public void agregarRueda(Rueda rueda) {
if(!ruedas.contains(rueda))
ruedas.add(rueda);
}
public boolean quitarRueda(Rueda rueda) {
return ruedas.remove(rueda);
}
public abstract void romperInercia();
}

Interfaz Desplazable



public interface Desplazable {
public abstract void esquivarObstaculo();
}

Clase Rueda



public class Rueda {}

Clase Barco



public abstract class Barco extends Vehiculo{}

Clase Auto



public abstract class Auto extends Vehiculo{
public static final int N_RUEDAS = 4;
}

Clase Moto



public abstract class Moto extends Vehiculo {
public static final int N_RUEDAS = 2;
public void esquivarObstaculo() {}
}

Clase Boing747



public class Boing747 extends Vehiculo{
private static int viajes;
@Override
public void romperInercia() {}
@Override
public void esquivarObstaculo() {}
public static int getViajes() {
return viajes;
}
public static void setViajes(int viajes) {
Boing747.viajes = viajes;
}
public void despegar() {}
public void aterrizar() {}
public static void agregarViaje() {}
}

Clase BarcoAVela



public abstract class BarcoAVela extends Barco {}

Clase FordFalcon



public class FordFalcon extends Auto {
@Override
public void romperInercia() {}
@Override
public void esquivarObstaculo() {}
}

Clase HondaXR600



public class HondaXR600 extends Moto {
@Override
public void romperInercia(){}
@Override
public void esquivarObstaculo(){}
}

Clase HondaXR25



public class HondaXR25 extends Moto{
@Override
public void romperInercia(){}
public void esquivarObstaculo(int metros){}
}

Más info sobre Diagramas de Clases en la etiqueta Diseño

viernes, mayo 21, 2010

UML, Asociacion y Agregacion

El post de la Agregación y Composición despertó otra pregunta más (Como siempre suele suceder, ya dije que el debate siempre dá para algo más). La duda viene por el lado de la diferencia entre asociación y Agregación en código. Se sostiene que es algo conceptual, que no se representa en código. Mi respuesta es que esto es 50% correcto. Ya que, como mencione antes (la etiqueta Diseño tiene mas sobre esto), la Asociación surgió primero, y la Agregación vendría a ser un tipo particular de Asociación. Ergo ...Agregacion "IS-A" Asociación ¡punto para ud! . Primero veamos el diagrama UML

Ahora veamos el codigo de la clase Persona (Nota: imagínense los generics por que blogspot los toma como tags, así que no aparecen)

import java.util.List;

public class Persona {

private String nombre;
private String apellido;

private Foto foto;
private List lugaresFrecuentes;
private List comunicaciones;

public String getNombre() {return nombre;}
public void setNombre(String nombre) {this.nombre = nombre;}
public String getApellido() {return apellido;}
public void setApellido(String apellido) {this.apellido = apellido;}

//Asociacion Foto
public Foto getFoto() {return foto;}
public void setFoto(Foto foto) {this.foto = foto;}

//public List getLugaresFrecuentes() {return lugaresFrecuentes;}
//public void setLugaresFrecuentes(List lugaresFrecuentes) {this.lugaresFrecuentes = lugaresFrecuentes;}

//Agregacion
public void agregarLugar(Lugar lugar){
lugaresFrecuentes.add(lugar);
}
public boolean quitarLugar(Lugar lugar){
return lugaresFrecuentes.remove(lugar);
}
//Asociación
public void setComunicaciones(List comunicaciones) {
this.comunicaciones = comunicaciones;
}
public List getComunicaciones() {
return comunicaciones;
}

}

Las diferencias principales son que:
  1. ¡La Agregación son siempre colecciones, o arrays! O algo que sirva de contenedor para "agregar" más de un objeto, aunque agreguemos uno solo. (si no sería settear y no agregar, add)
  2. La Agregación cuenta con dos métodos: uno para "agregar" un solo objeto a la lista, y el otro para quitarlo de la misma.
  3. La agregación puede, como no, tener los metodos setter y getter, mientras que la Asociación siempre los tiene, que ponen y obtienen una variable de referencia del mismo tipo de la variable de instancia o de clase, en este caso List.

Bueno, espero haber limpiado alguna duda, y abrir otras ;) Saludos.

jueves, mayo 13, 2010

UML, Agregacion y Composicion

He visto demasiadas discusiones vicentinas sobre las diferencias entre la agregación y la composición en los diagramas de clases de UML. Es más, cada cierto tiempo, alguien surge y me pregunta cual es la diferencia en el código y me explica sus propias teorías sobre esta cuestión, este debate es casi tan extenso como el de los extends y los includes de los casos de uso.
Empecemos, debemos recordar siempre que una de las mayores criticas que recibe UML, es que ha logrado salvar muchas ambigüedades... Pero no todas!!! aun quedan conceptos que se prestan a dobles interpretaciones, no se si este será uno de ellos, pero por lo discutido parece que sí. Por otro lado, podemos hacer un poco de historia, recordando que primero existió la asociación, después surge la Agregación para representar un relacion estructural contenedor/contenido y luego como una "extensión" de esta ultima nace la Composición.
Para explicar mi punto de vista voy a echar mano, al diagrama de clases que ya he utilizado en otro post y después voy a poner el código de la clase Persona, que es la que se lleva toda la carga de la discusiónEl código hace referencia, solo a este modelo, y es bien detallado, hasta con cosas innecesarias, o meramente teóricas, pero lo que busco es fijar una posición, concreta y definitiva, en el tema de las relaciones.
Algo importante a tener en cuenta, es que un objeto existe (digamos que esta vivo, pero esto no es técnicamente correcto por que no es un hilo) mientras existe una variable de referencia que "apunte" (tampoco correcto, por que java no tiene punteros, je) a dicho objeto en memoria. Es decir que se convertirá en elegible para ser borrado por el garbage collector, cuando no exista una variable que "apunte" a dicho objeto.


import java.util.LinkedList;
import java.util.List;

public class Persona {
private String nombre;
private String apellido;
private List perfiles = new LinkedList();
private List lugaresFrecuentes = new LinkedList();

//Setters and Getters
public String getNombre() {return nombre;}
public void setNombre(String nombre) {this.nombre = nombre;}
public String getApellido() {return apellido;}
public void setApellido(String apellido) {this.apellido = apellido;}

// OJO no confundir estos son solo setters y getters de las propiedades
public List getPerfiles() {return perfiles;}
public void setPerfiles(List perfiles) {this.perfiles = perfiles;}
public List getLugaresFrecuentes() {return lugaresFrecuentes;}
public void setLugaresFrecuentes(List lugaresFrecuentes) {this.lugaresFrecuentes = lugaresFrecuentes;}

La clase comienza normalmente con la declaración de las variables de instancia. Donde perfiles y lugaresFrecuentes son dos colecciones, pero tranquilamente podrían ser arrays. que se transformarán en contenedores de elementos. Al ser propiedades tienen getters y setters (accessors y mutators), que nada tienen que ver con la agregación y la composición.
Ahora veamos cuales son los métodos que caracterizan a la relación de AGREGACIÓN


public void agregarLugarFrecuenta(Lugar lugar){
if(!lugaresFrecuentes.contains(lugar)){
lugaresFrecuentes.add(lugar);
}
}
public void removerLugarFrecuenta(Lugar lugar){
if(lugaresFrecuentes.contains(lugar)){
lugaresFrecuentes.remove(lugar);
}
}

La primera característica es que la clase contiene dos métodos uno que agrega elementos a la coleccion y otro que los elimina de ella. He acá algo importante... los objetos son pasados por parametro, no han sido instanciados dentro del método, es decir no hemos realizado el new del objeto. Ha "nacido" en cualquier otra parte y se lo hemos pasado por parámetro al método para ser agregado a la lista lugaresFrecuentes. En otras palabras, el objeto Persona podria morir, y el objeto ahun podría mantener una referencia activa en alguna otra parte de nuestro codigo por lo tanto sus ciclos de vida no estrían atados. No nace ni muere, dentro de la Persona.

¿Cual es la Diferencia con la COMPOSICIÓN?


public void agregarPerfil(){
Perfil p = new Perfil();
perfiles.add(p);
}
//sobrecarga
public void agregarPerfil(String nombre){
Perfil p = new Perfil(nombre);
perfiles.add(p);
}
public void removerPerfil(int index){

perfiles.remove(index); // aca lo quitamos de la lista

}
Bueno... la composición también tiene los métodos para agregar y borrar. Pero...

"el new del objeto se realiza dentro del método agregar"


la instanciación del objeto p se realiza dentro del método agregar y la referencia no se devuelve (es void o boolean), la variable de referencia local va a dejar de existir una vez que el método se termine de ejecutar, y el ciclo de vida de esa instancia en particular va a quedar atada a la lista, y por ende a la Persona. Una vez que el objeto Persona no se referencie más, (o sea muera, aunque técnicamente esto no es así) el objeto lista, quedará sin referencia, y por lo tantos sus elementos también. Además como el método no es estático, se deberá crear primero una instancia de Persona, para después poder agregar un Perfil. Empezando así a "atar" el ciclo de vida de un Perfil, al de una Persona.
En cuanto al método remover, no existe nada de extraordinario, simplemente quitamos un elemento de la lista.

Volviéndonos Paranoicos de la Teoría


Profundizando la paranoia y jugando con la teoría; para que atemos definitivamente los ciclos de vida, la variable lugaresFrecuentes no debería ser una propiedad, y la clase Perfil debería ser una Inner Class.
En el caso de la Inner class, hacemos esto para que se tenga que utilizar una instancia de la clase "Outer" para luego obtener una instancia de la clase Inner. Por ejemplo si en nuestro codigo, la clase Perfil, fuera una Inner class de la clase publica Persona (Se entiende no?, es decir que esta dentro del archivo Persona.java), para obtener una instancia de Perfil fuera de la clase persona tendríamos que hacer:

Persona persona = new Persona();
Persona.Perfil perfil = persona.getPerfil(...);

El new de creación esta dentro del metodo agregarPerfil. La clase Perfil existiría mientras exista la instancia de persona. (ciclos de vida atados)
En el caso de que la variable de instancia lugaresFrecuentes no debería tener getters y setters públicos, esto se debe a que ningún otra clase, con excepción de la clase Persona, debería tener la oportunidad de mantener una referencia viva a un objeto del contenedor. Y mucho menos obtener toda la Lista desde afuera! Un objeto Perfil, vive y muere con la Persona!
También de esto se pueden desprender otros delirios, como cuestiones de herencia y cosas así.
Pero de nuevo, y no me voy a cansar de decirlo... esto es un extremo!!, es solo para conversar entre amigos, o vanagloriarse con algún profesor, no tiene nada de practico, ni de real, salvo para casos específicos.

Paranoia de la Paranoia


¿Creían que ya habíamos terminado? aun se puede ser más paranoico!!!! mucho se ha discutido sobre estos temas, y mucho fue paranoia teórica. Lo siguiente, es algo que les llevará a sus amigos o profesor a decir, "...bueno pero eso ya es una locura":
Sobreescribiremos el método finalize() de la Clase Persona, que es un método que todas las clases heredan de Object, y que se invoca justo antes de que un objeto sea borrado de la memoria por el garbage collector de java.

public void finalize(){
for(Perfil p : perfiles){
p = null;
}
}

En el desreferenciamos cada uno de los elementos de la lista un segundo antes de que el objeto de tipo Persona desaparezca de la memoria, una milésima de segundo, o algo asi!!! atando definitivamente el nacimiento y muerte, el ciclo de vida, de un elemento contenido con su contenedor.
Pero de nuevo!!! LA PARANOIA EN EL CÓDIGO NO ES BUENA!!! solo sirve en aquellas noches de borrachera entre programadores, en las cuales el boliche cerró y pinta quedarse en casa con amigos.

Yo rescataría de todo este biri-biri aquello de "el new se realiza dentro del método" y nada más!!!

miércoles, mayo 12, 2010

SCJP 1.6 de Java


Hace unas semanas a tras he decidido rendir la certificación SCJP 1.6 de Java. La verdad es que en un principio, me resultaba medio confusa y bastante difícil. Pero después a medida que estudiaba el libro, y lo traducía de apoco, por que la única versión que existe es en ingles, y además el examen es en inglés, fui adquiriendo un mayor ritmo para la resolución de los ejercicios. Creo haber aprendido un montón de cosas que desconocía a cerca del lenguaje. Esta muy buena y es super aconcejable, así qué, cuando tengan un tiempo (notece que dije tiempo y no tiempito) se pueden encomendar a esta campaña. Existe info de sobra en la web de como rendirla, o sea vasta googlear "SCJP 1.6 de Java" para toparce con foros, blogs y paginas que contienen PDFs con manuales, algununos simuladores, jugos etc. Lo que no se encuentra a simple vista es tips y estrategia para afrontar el examen.
En mi caso personal, y al conversar con algunos amigos que ya la habían rendido, me dí cuenta que la clave principal, es el TIEMPO, repito en mi caso personal, ya qué no sé si todas las versiones del examen serán iguales, pero contaba con 60 preguntas, y un tiempo máximo de resolución de 3hs. Que si contamos con los deditos nos da un total de 3 minutos por pregunta. Bien, existen preguntas que exeden por lejos ese tiempo, ya que tienen codigo largo, confuso y si además le sumamos que hay demaciadas preguntas tramoposas en el examen, por lo que por más que seamos "don java" si nos dormimos por un segundo, se nos va a pasar algun import o punto y como o algo así. Yo no sabía cual sería la duración, ni cuantas preguntas tendría, por que cada pagina daba una duracion diferente, por lo que decidí entrenarme con un timpo de resulución de 4 minutos por pregunta, con las preguntas del libro, y ni ahun así lograba resolverlas a todas. Llegado el dia, y al darme cuenta que solo tenia 3 minutos, decidí, no escarbar tanto en las preguntas, y si tenian "trampa" que así sea. La hipotesis fué que serían las menos. Y para ser mi primer intento, logré certificar. Es más me quedo unos 15 minutos para hacer una rápiada repasada del examen donde logre reveer un 30% de las preguntas y salvar 2.
Algunos datos utiles en argentina:

- Tiempo de duración: 3hs (180 min)
- Total de Preguntas: 60
- Score para aprobar: 58% (35 Preguntas)
- Ojo con las preguntas de arrastrar y soltar se pueden resetear
- Codigo del examen: 310-065
- Libro (PDF): Sun Certified Programmer for Java 6 - Study Guide
- Libro en Papel: Sun Certified Programmer for Java 6 - Practice Exams (No se molesten en buscarlo en PDF, solo sale la versión en papel, Y NO LO TENGO, por lo que si alguien lo tiene en PDF me lo podría habilitar.
- Simuladores: Wizlabs, Sybex, intrepid
- 1 Blog: http://scjp-sun.blogspot.com/
- Juegos para practicar: http://faq.javaranch.com/java/ScjpMockTests
- info sobre la certificacion: http://osum.sun.com/
- Donde inscribirse para rendir: www.prometric.com



Lic Ariel Diaz Molina
Java Certified Programmer

jueves, septiembre 06, 2007

Ventanas en Java II, Ventanas Internas, Frames Internos: JInternalFrame, JDesktopPane


Para Nai y Eve


Volvamos a repasar unos conceptos básicos sobre las ventanas en java. Tres son los tipos de ventas mas usadas en Java en lo que a Swing respecta.
Los JFrames comunes y corrientes. Que son esas ventas que se van creando en la barra de tareas si usas Windows.

JDialog que son ventanas, por lo general modales, en las cuales debe responder antes de continuar con las otras ventanas. Son ejemplos de dialogos, aquellas ventanas donde se nos solicita insertar la ubicación donde queremos guardar un archivo.
JInternalFrames
: Esta es una clase particular de ventanas. Las cuales se encuentran inmersas en una ventana padre, que hace las veces de escritorio. Actualmente la mayoría de las aplicaciones de escritorio, siguen este formato. Estas ventanas pueden ser minimizadas y expandidas dentro de los límites de la ventana padre.
En este pequeño tutorial veremos las JInternalFrames.

Creando un JInternalFrame

1er Paso: Crear el Frame Padre

El primer paso que debe realizar a la hora de trabajar con InternalFrames es crear la ventana que contendrá los internalFrames. Esta ventana ser padre de todas las demás es decir que el ciclo de vida de todas las ventanas internas se encontrara atada a esta.
Esta ventana padre, será un frame común y corriente.


public class FramePadre extends JFrame implements ActionListener{
JDesktopPane escritorio = new JDesktopPane();// escritorio de Trabajo
JMenuBar barra =new JMenuBar(); // barra de menu
JMenu menu =new JMenu("Archivo");
JMenuItem itemInterna =new JMenuItem("Internal Frame");
JMenuItem itemSalir =new JMenuItem("Salir");
public FramePadre() {
this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
……
}
}

Como vemos extiende a JFrame e implementa la interfaz ActionListener, para captar los eventos de una barra de menú que ingresamos. En este tutorial no desarrollaré como crear una barra de menú, pues mi política es encarar cada cosa por separado, mas adelante lo realizare, pero si mostrare el código para poder realizarlo.
Además de ello podemos ver como declaramos una variable escritorio del tipo JDesktopPane, esto nos permitirá asignar una superficie de trabajo que delimitara a los internalFrames.
Dentro del constructor de la clase podemos llamar un método que creamos para ordenar la creación de la interfaz grafica, o directamente poner el siguiente código.

Dimension tamaño =Toolkit.getDefaultToolkit().getScreenSize();//de la pantalla
this.getContentPane().setLayout( null );
this.setBounds(0,0,tamaño.width,tamaño.height-30);
this.setTitle("Ejemplo Escritorio");
this.itemInterna.addActionListener(this);//para captar el evento en el ítem
this.itemSalir.addActionListener(this);//idem anterior
menu.add(this.itemInterna);//la menu le agregamos el item
menu.add(this.itemSalir);// idem anterior
this.barra.add(menu);// a la barra le agregamos el menu
this.setJMenuBar(barra);// al frame le agregamos la barra.
escritorio.setBackground(new Color(251,255,235));// un colorcito p escritorio
this.setContentPane(escritorio);// agregamos el escritorio al frame

Una vez terminado con esto, solo nos resta crear el método para captar los clic que realizara el usuario sobre cada uno de los ítems del menú. Es así como declaramos el método actionPerformed, impuesto por la interfaz ActionListener, e indicamos que realizar ante cada uno de los eventos de usuario.

public void actionPerformed(ActionEvent e){
if(e.getSource()==this.itemSalir){
this.salir();
}
if(e.getSource()==this.itemInterna){
FrameInterno interno =new FrameInterno("Ejemplo Frame Interno");
escritorio.add(interno);// Agregamos el frame al escritorio
try {
interno.setSelected(true);// Decimos que comience Enfocado
} catch (PropertyVetoException e) {}
}
}

Como vemos en el caso de que el usuario haga clic en el menú itemInterna se instancia un internalFrame y luego se lo agrega al escritorio. Finalmente decimos que se inicialice enfocado y capturamos la excepción.

2do Paso Crear un Internal Frame

Para crear nuestro frame interno, tenemos que crear una clase que herede de javax.swing.JInternalFrame:


public class FrameInterno extends JInternalFrame implements ActionListener{
…//components Swing, botones, label etc
public FrameInterno(String titulo) {
super(titulo,
true, //redimencionar
true, //cerrar
true,//maximizar
true);//minimizar
try{
interfazGrafica();
this.setVisible(true);
}
catch(Exception e){}
}
}
Como vemos podemos definir los botones que contendrá el frame en el ángulo superior derecho. Esto lo definimos pasándole como argumentos a la súper clase valores boléanos si queremos permitir eso.

Luego en el metodo interfazGrafica(), escribimos toda la interfaz que podría ser:


private void interfazGrafica() throws Exception {
this.getContentPane().setLayout(null);
this.setSize(new Dimension(311, 347));
btn_cerrar.setText("Cerrar");
btn_cerrar.setBounds(new Rectangle(180, 270, 110, 30));
jLabel1.setText("Este es Un Frame Interno");
jLabel1.setBounds(new Rectangle(30, 65, 255, 35));
jLabel1.setFont(new Font("Dialog", 1, 20));
jLabel1.setForeground(Color.blue);
this.btn_cerrar.addActionListener(this);
this.getContentPane().add(jLabel1, null);
this.getContentPane().add(btn_cerrar, null);
}

Y finalmente tenemos que hacer visible el frame con setVisible
Por ultimo debemos definir el método al cual nos obliga la interfaz ActionListener

public void actionPerformed(ActionEvent e){
if(e.getSource()==this.btn_cerrar){
this.setVisible(false);
}
}

Con esto ya tenemos un frame básico a partir del cual podemos empezar a jugar y agregarle componentes como botones y label o cualquier otra cosa que se les ocurra.
No dejen de ver que bueno que queda cuando minimizan un internalFrame!!

Saludos

lunes, septiembre 03, 2007

Confirmación y Alertas en Java: JOptioPane, showMessageDialog, showConfirmDialog, showInputDialog , showOptionDialog

La clase JOptionPane es una clase que hereda de JComponent. Ésta clase nos permitirá crear alertas o cuadros de diálogos simples para poder solicitar, o mostrar, información al usuario.
Los métodos que revisaremos en este pequeño tutorías serán:

  1. JOptionPane.showMessageDialog(…)
  2. JOptionPane.showConfirmDialog(….);
  3. JOptionPane.showInputDialog(…);
  4. JOptionPane.showOptionDialog(…);

Cada uno de estos métodos presenta una particularidad distinta pero todos ellos nos muestran una ventanita pop up que nos permitirá captar información del usuario.

  1. showMessageDialog

JOptionPane. showMessageDialog (Component componentePadre, Object mensaje, String titulo, int tipoDeMensaje)

Nos sirve para mostrar información, por ejemplo alguna alerta que queremos hacerle al usuario. Veamos cuales son los principales argumentos del método.
componentePadre: es por el ejemplo el Frame desde el cual lo llamamos. Si queremos lo podemos poner en null, que es mas o menos lo mismo.
Mensaje: es lo que queremos que diga el cuadro de dialogo.
Titulo: el titulo.
tipoDeMensaje: son constantes que le dirán a java que tipo de mensaje queremos mostrar. De acuerdo a esto seran los iconos que se mostraran en el cuadro de dialogo. Las opciones son

  • ERROR_MESSAGE
  • INFORMATION_MESSAGE
  • WARNING_MESSAGE
  • QUESTION_MESSAGE
  • PLAIN_MESSAGE

Si quisiéramos mostrar un icono personalizado, podemos agregarlo al final como un argumento más.
Ejemplo:

JOptionPane.showMessageDialog(null,"Acceso Denegado","Error",
JOptionPane.ERROR_MESSAGE);

  1. showConfirmDialog

Éste método sirve para pedirle al usuario una confirmación. Por ejemplo una confirmación de salida del sistema

Int respuesta =JOptionPane. showMessageDialog (Component componentePadre, Object mensaje, String titulo, int tipoDeOpcion);

El anterior es la versión corta del los argumentos del método. La versión larga incluye el tipo de mensaje y el icono, por si queremos personalizarlo.
Los argumentos son idénticos a los del método anterior. Excepto por el tipo de opción, que es otra constante y los valores pueden ser:

  • DEFAULT_OPTION
  • YES_NO_OPTION
  • YES_NO_CANCEL_OPTION
  • OK_CANCEL_OPTION

Como vemos el método devuelve una un entero que nos permitirá captar cual es la opción elegida por el usuario. Los valores serán 0 para Si, 1 para No, 2 para Cancelar y -1 para el cierre de la ventana. Así podremos preguntar cual es el valor devuelto y realizar la acción que deseamos.
Ejemplo

int i =JOptionPane.showConfirmDialog(this,"¿Realmente Desea Salir de Hola Swing?","Confirmar Salida",JOptionPane.YES_NO_OPTION);
if(i= =0){
System.exit(0);
}

  1. ShowInputDialog

Este método nos muestra una ventana donde podremos insertar una String. Por ejemplo cuando queremos que el usuario inserte su nombre. La versión corta del método es

String respuesta = JOptionPane.showInputDialog(Object mensaje)

Este método devolverá una String para poderla utilizar después. La versión larga de los argumentos del método es similar a los anteriores.
Ejemplo:

String nombre =JOptionPane.showInputDialog("Inserte su Nombre");
this.lbl_nombre.setText(nombre);

También podemos crear un cuadro de dialogo que contenga un combo con las opciones predeterminadas que le queremos dar al usuario.
Ejem:

Object[] valoresPocibles = {"Pedro", "Juan", "Carlos" };
Object jefe = JOptionPane.showInputDialog(null,
"Seleccione cual es su Jefe Inmediato", "Seleccionar Jefe",
JOptionPane. QUESTION_MESSAGE, null,
valoresPocibles,
valoresPocibles[0]);
this.lbl_jefe.setText((String)jefe);

El array de valores posibles nos muestra en un combo cuales serán los jefes que podemos mostrar. El último argumento del método nos muestra cual será la opción seleccionada por defecto

showOptionDialog

Con este método podemos crear cuadros de diálogos con botones personalizados. Esta bueno para darle un toque personal a los cuadros de dialogo
El método tiene la forma:

Int res = JOptionPane.showOptionDialog(Component componentePadre, Object mensaje, String titulo, int tipoDeOpcion, int tipoMensaje, Icon icono, Object[] botones, Object botonDefault)

Aquí lo único que varia con el resto es el array de botones que vamos a tener, debemos destacar que no hace falta que creemos botones, solo tenemos que poner cual será el texto que saldrá en el.

Object[] botones = {"Si dale va a estar bueno", "No?... buuu" };
int i=JOptionPane.showOptionDialog(null, "¿Queres salir a Bailar esta Noche?", "Sita",
JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,null, botones, botones[0]);
System.out.println(i);

Después podemos tomar la respuesta como lo hacíamos con el confirmDialog.
Bueno hasta la próxima, esto es lo más importante en los mensajes o alertas.

miércoles, agosto 29, 2007

Ventanas en Java I: JFrame, propiedades, centrar, confirmar al cerrar, eventos


La primera distinción que debemos hacer entre las ventas que vamos a realizar es si las mismas son modales o no. Las modales son aquellas ventas que si o si deben tener una respuesta del usuario antes de continuar, como por ejemplo aquellas ventanas donde se nos pide que confirmemos si queremos guardar un archivo o no. Todas las demás ventanas son no modales.
En estos pequeños tutóriales, voy a desarrollar JFrames, IInternalFrames y JDialog
En el caso de las JFrame las mismas son no modales.

1. JFrame

Para comenzar a crear un JFrame tenemos que crear una ventana que extienda la clase JFrame e implemente la interfaz ActionListener que nos permitirá captar los eventos de los usuarios sobre los componentes Swing que vamos a utilizar (el botón).

public class FrameInicial extends JFrame implements ActionListener{

//variables globales en este caso Irán todos los componentes swing
//Constructor de la case
//Métodos

}

Debemos recordar que siempre que implementemos la interfaz AL deberemos declarar el método actionPerformed(AcrionEvente evento)
El constructor de la clase tendrá la forma:

public FrameInicial() {
try {
metodoSiguiente();
// aquí vamos a poner las propiedades y componentes
this.centrar();
//método mió para centrar
/*confirmacion de salida*/
this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
addWindowListener( new WindowAdapter() {
public void windowClosing(WindowEvent e) {
confirmarSalida();
}
});
this.setVisible(true);
//hacemos visible el frame
}
catch (Exception e) {
e.printStackTrace();
}
}

El metodoSiguiente() es un método que cree para ordenar todas las propiedades y los componentes que contendrá nuestra ventana.
Centrar() es un método que nos permitirá centrar la ventana de acuerdo a la resolución que tenga nuestro monitor. Por defecto en java todas las ventanas aparecen en el extremo superior izquierdo.
En cuanto a solicitar una confirmación a la hora de salir lo primero que tenemos que indicar es que la ventana no va a realiza ninguna acción cuando se da el evento de cierre, si esto no se especifica, la ventana sale directamente sin realizar ninguna acción. Esto es en el caso en que tenemos un frame que es el principal de nuestra aplicación y queremos pedirle al usuario que confirme la salida cuando hizo clic en la crucecita del frame.
Lo hacemos con el metodo:

setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE)

confirmarSalida() será el método que pregunte si deseamos salir o no.
Finalmente debemos hacer visible el frame con el método setVisible(true).

1.1 metodoSiguiente()

En este caso vamos a agregarle al frame una label y un botón para cerrar, a medida que vallamos avanzando en los distintos frames voy a ir agregando distintos componentes.
Es una buena costumbre nombrar a los componentes de forma representativa.
Por ejemplo las etiquetas pueden comenzar con lbl_nombre o los botones con btn_nombre, etc. Ya que cuando nuestra aplicación crezca se puede hacer complicado si no tenemos nombre representativos. Otra aclaración es que los componente ya fueron declarados e inicializados globalmente en la case.

private void metodoSiguiente() throws Exception {
this.getContentPane().setLayout( null );//la forma de organizar los componentes
this.setSize(new Dimension(385, 300));
//el tamaño de la ventana
this.setTitle("Hola Swing");
//el titulo
btn_cerrar.setText("Cerrar");
//el boton cerrar
btn_cerrar.setBounds(new Rectangle(250, 220, 120, 25));//tamaño del botón
lbl_hola.setText("Hola Swing");//lo que la etiqueta dirá
lbl_hola.setBounds(new Rectangle(135, 80, 120, 35));//el tamaño de la etiqueta
lbl_hola.setToolTipText("texto emerguente");
//texto mouse por arriba
lbl_hola.setFont(new Font("Dialog", 1, 20));
//la fuente de la etiqueta
lbl_hola.setForeground(Color.red);
//color de la etiqueta
this.btn_cerrar.addActionListener(this);
//para escuchar los eventos.
this.getContentPane().add(lbl_hola, null);//pegar los components en el frame
this.getContentPane().add(btn_cerrar, null);
}


El setLayout es la forma en la que organizamos los componentes dentro del frame, esto nos servirá para cuando el frame cambie de tamaño o se maximice los componentes mantengan un aspecto armónico. Es todo un tema los distintos tipos de layout que existen en java.
El size o tamaño del componente es importante a la hora de centrar el frame en la pantalla, ya que lo utilizaremos para calcular la ubicación en la que debe estar. Se pasa como parámetro un objeto dimensión con los valores del (ancho, alto).
El titulo (setTitle) es el texto que aparecerá en la parte superior del frame, ademas cuando lo minimicemos aparecerá en la barra de herramientas de Windows (o superior)
En el caso del btn_cerrar le diremos cual será el texto con contendrá con setText, el tamaño y la ubicación con el método setBounds que recibe como parámetro un objeto Rectangle con parámetros que indican las coordenadas y tamaño. Los dos primeros son las coordenadas en x e y desde el margen superior izquierdo del frame, y los dos restantes son el tamaño en ancho y alto.
En cuanto a la etiqueta lbl_hola podemos definir que dirá con setText, la ubicación y tamaño con setBounds, y lo que dira cuando pasemos con el Mouse por arriba con setToolTipText, esta misma propiedad puede ser aplicada a otro componentes swing para ir guiando al usuario. Además de ello podemos indicarle cual sera la fuente que la etiqueta tendrá con setFont que recibe como parámetro un objeto del tipo Font que indica (el nombre de la fuente, normal/negrita/itálica, tamaño). Finalmente podemos indicarle el color que tendrá el texto con setForeground que recibirá como parámetro una constante que indique el color o un objeto Color con parámetros (R,G,B).
componente.addActionListener(this) es el método que permite agregar un oyente de eventos a un componente que tendremos dentro del frame. En este caso se lo agregaremos al botón de cerrar por que nos interesa saber cuando el usuario hace un clic en el. Decimos que el parámetro será el frame que creamos por que ya hemos implementado la interfaz ActionListener en el frame si no tendríamos que crearla como lo hicimos en el caso de la ventana.
Bien… ya hemos creado todos los componentes que el frame tendra, ahora tenemos que pegarlos en frame, si no, no serán visibles, esto los haremos con el método add(componete), que tiene como parámetros ya sea el componente solo, o el componente con su correspondiente layout.

Nota: a estas alturas, los que recién comienzan dirán es un kilombo total crear interfaces graficas en Java, pero no se asusten, los entornos de desarrollo tienen sus propias herramientas para crear esto arrastrando y soltando. ¡Es más! este ejemplo fue creado de esa forma. La finalidad es que sepamos que hace cada cosa.

1.2 El método Centrar()

Al igual que el método anterior, éste es un método creado por mí para centrar las ventanas. Como idea se puede crear una clase con el método implementado y después heredarla en otras clases, en fin… son solo idas.

private void centrar(){
Dimension pantalla = Toolkit.getDefaultToolkit().getScreenSize();
Dimension frame =this.getSize();
setLocation((pantalla.width/2-(frame.width/2)),pantalla.height/2-(frame.height/2));
}

Lo primero que realiza el método es tomar la resolución de la pantalla, primero obtiene el toolkit por defecto y después el resolución de la pantalla.
Después el tamaño que le dimo al frame con getSize()
Y finalmente le indicamos la localización del frame en la pantalla con el método setLocation(int x, int y)

1.3 El método confirmarSalida()

A este método lo podremos llamar tanto desde el botón cerrar de la ventana misma como de un botón creado por nosotros mismos. La llamada al método se realizará en los métodos que las interfaces que escuchan los eventos de usuario, en el caso de la ventana es windowClosing(WindowEvent e), y en el caso del botón es actionPerformed(ActionEvent e).

private void confirmarSalida(){
int i =JOptionPane.showConfirmDialog(this,"¿Realmente Desea Salir de Hola Swing?","Confirmar Salida",JOptionPane.YES_NO_OPTION);
if(i==0){
System.exit(0);
}
}

Bien acá hay algo interesante relacionado a las ventanas. JOptionPane es una clase que nos permite hacer cuadros de diálogos. En el caso del método showConfirmDialog nos devolverá un entero con el valor de la elección del usuario. (En este caso 0 para si, 1 para no). Veremos más opciones cuando trate diálogos en Java.
El método exit(int status) de la clase System nos permitirá cerrar nuestra aplicación.
Debemos distinguirlos del método JFrame.setVisible(boolean visibilidad) del frame que nos permite cerrar la ventana sin salir de la aplicación.

1.1 El método actionPerformed(ActionEvent evento)

Este método nos permitirá captar los eventos realizados por el usuario sobre algún componente swing, en nuestro caso será el botón.

public void actionPerformed(ActionEvent e){
if(e.getSource()==this.btn_cerrar){
confirmarSalida();
}
}

Lo primero que realizamos dentro del método es preguntar cual es la fuente del evento, esto lo hacemos en caso de que tengamos varios botones a los cuales le asignamos el oyente de eventos. Si la fuente del evento es el botón cerrar, llamamos el método confirmar salida.

1.2 La clase Principal

Es una buena costumbre tener una clase que contenga el método main y desde la cual llamar al formulario de entrada a la aplicación.

public class Principal {
public Principal() {
FrameInicial f =new FrameInicial();
}
public static void main(String[] args) {
Principal principal = new Principal();
}
}

martes, agosto 28, 2007

Iniciando Java

Hablando con amigos que recién se estaban iniciando en java me preguntaban como podían hacer interfaces graficas en Java, como podían bajar lo que habían teorizado en las aulas a la programación neta.
Un buen comienzo, es empezar en las UI tipo Swing o AWT, algunos pensaban que este tipo de paradigmas se estaban olvidando frente a las interfaces WEB, pero JSF nos vuelve a remontar a la captación de los eventos realizados por el usuario.
La estructura de estos post vendrán dados como si construyéramos una aplicación, no me animaría a decir que seguiré el modelo MVC (modelo-Vista-Control) pero si a que definiré los aspectos mas importantes.
Otro aspecto a tener en cuenta el IDE o entorno de desarrollo que vamos a utilizar, ya que éste nos permitirá ahorrarnos un buen trabajo. En mi caso, pero no quiero decir que sea el mejor, utilizaré JDeveloper.

lunes, noviembre 20, 2006

Tablas en java I –Jtables, Modelos,TableModel, JScrollPane

Las tablas en java son otros de los componentes difíciles de crear para los usuarios inexpertos. Quizás por sus grandes capacidades y posibilidades de utilización, es que no se crean con un simple arrastrar y soltar con nuestro ide favorito, o por lo menos no como nosotros queremos.
Importando javax.swing.JTable ya estaremos en condiciones de empezar a crear tablas. Pero a los fines de explicar la forma más sencillas de crearlas, no comenzaremos por ahí. Ya que, a mi entender, lo mas fácil es crear un modelo de tabla que luego utilizaremos. Luego crearemos la tabla, y finalmente crearemos el JScrollPane que la contendrá, para hacer la tabla escrolable.

Creando un Modelo de Tabla –TableModel

El modelo de tabla será aquel que determine la forma que nuestra tabla tendrá, y su comportamiento ante los eventos.
Generalmente utilizamos un tabla para listar algo, o cargar datos de forma rapida, por ejemplo personas. En este ejemplo utilizare una clase Personas que tiene tres atributos: Apellido, Nombre (Strings) y número de documento (int).
Lo primero que hay que hacer es crear una clase que implemente la interfaz TableModel. En dicha clase se instanciaran tres variables; dos del tipo LinkedList y una del tipo Persona.

public class MyModelo implements TableModel{
private LinkedList datos = new LinkedList();
private LinkedList listeners = new LinkedList();

Peronas persona =new Peronas();

….
}

La clase LinkedList es una especie de lista que permite incluir y manejar elementos a través de operaciones. Pudiendo ser de cualquier tipo, incluso null. Esta clase nos brinda métodos uniformados para insertar, borrar, obtener y poner elementos en la lista.
La implementación de la interfaz TableModel nos obliga a la utilización de algunos métodos que mostrare a continuación:

1)
public int getColumnCount() {
return 3;
}

Este metodo determina la cantidad de columnas que la tabla tendera. Por ejemplo si queremos que la tabla tenga 3 debemos retornar el numero 3

2)
public int getRowCount() {
return datos.size();
}

Retorna la cantidad de filas, se basa en la lista de elementos declarada con anterioridad.

3) Hora viene uno de los métodos mas importantes el que servirá para obtener los datos de la lista.

public Object getValueAt(int rowIndex, int columnIndex) {
Personas aux;
//castemos el dato de la lista a una variable del tipo Personas
aux = (Personas)(datos.get(rowIndex));
// Se obtendra la persona seleccionada según el numero de fila
switch (columnIndex)
{
case 0:
return aux.getDni();
case 1:
return aux.getApellido();
case 2:
return aux.getNombre();
default:
return null;
}
}

4) asi como tenemos el metodo get existe el metodo set

public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
Personas aux;
aux = (Personas)(datos.get(rowIndex));
switch(columnIndex)
{
case 0:
aux.setDni((Integer)aValue);
break;
case 1:
aux.setApellido((String)aValue);
break;
case 2:
aux.serNombre((String)aValue);
break;
default:
break;
}

TableModelEvent evento = new TableModelEvent (this, rowIndex, rowIndex,
columnIndex);
avisaSuscriptores (evento);
}

aValue es un objeto que se pasa como parametro y que contendrá, en nuestro caso, a la persona, pero para convertirla primero debemos castearlo.
Un TableModelEvent se utilizar para notificar a los suscriptores (todos aquellos que necesitan conocer las actividades que se realizan sobre el modelo, por ejemplo la tabla) que el tablemodel a cambiado.

5)
public Class getColumnClass(int columnIndex) {
// Devuelve la clase que hay en cada columna.
switch (columnIndex){
case 0:
return Integer.class;
case 1:
return String.class;
case 2:
return String.class;
default:
return Object.class;
}
}

Nos permitirá obtener las clases de cada columna para utilizarla después.

6)
public String getColumnName(int columnIndex) {
switch (columnIndex)
{
case 0:
return "DNI";
case 1:
return "Apellido";
case 2:
return “Nombre”;
default:
return null;
}
}
Este metodo permite definir el nombre de los campos que saldran en el encabezado de la tabla.

7)
public boolean isCellEditable(int rowIndex, int columnIndex) {
return true;
}

Determina si la celda es editable, nosotros podemos jugar con condicionales para determinar que columnas serán editables y cuales no. En este caso todas las celdas son editables.

8)
public void addTableModelListener(TableModelListener l) {
// Añade el suscriptor a la lista de suscriptores
listeners.add (l);
}

9)
public void removeTableModelListener(TableModelListener l) {
// borra un suscriptor
listeners.remove(l);
}

Una ves que terminamos con todos lo métodos que se nos exige implementar, podemos empezar a crear nuestros propios métodos para el manejo de los datos de las celdas.
Lo primero que aremos será crear el método que avise a los suscriptores que el modelo a cambiado y por lo tanto la tabla deberá cambiar.

private void avisaSuscriptores (TableModelEvent evento){
int i;
for (i=0; i
((TableModelListener)listeners.get(i)).tableChanged(evento);
}

Después comenzaremos a crear los metodos para insertar, borrar y acualizar las personas de la tabla

Insertar

public void insertarPersona (Personas nuevaPersona){
// Añade la persona al modelo
datos.add (nuevaPersona);
// Avisa a los suscriptores creando un TableModelEvent...
TableModelEvent evento;
evento = new TableModelEvent (this, this.getRowCount()-1,
this.getRowCount()-1, TableModelEvent.ALL_COLUMNS,
TableModelEvent.INSERT);
// ... y avisando a los suscriptores
avisaSuscriptores (evento);
}

Con el metodo LinkedList.add() agregamos un elemento a la lista de elemntos que contiene los datos de las personas. Después de ello debemos crear un TableModelEvent que permita notificar de la inserción del dato a la lista.

La estructura del constructor del TableModelEvent que utilizamos es:

TableModelEvent(TableModel modeloDeTabla, int filaInicio, int filaFin, int columna, int tipoEvento)

En este caso en particular, estamos incertando en la ultima fila por que la fila de inicio y de fin es la misma , los cambios se realizarán en todas las columnas, y el evento es un INSERT.

Borrar

public void borrarPerona (int fila){
datos.remove(fila);
TableModelEvent evento = new TableModelEvent (this, fila, fila,
TableModelEvent.ALL_COLUMNS, TableModelEvent.DELETE);

avisaSuscriptores (evento);
}

Similar a al anterior pero para borrar.

Actualizar

public void updateTurno(Turnos turno_completo, int fila){
datos.remove(fila);
datos.add(fila,turno_completo);
TableModelEvent e =new TableModelEvent(this,fila,fila,TableModelEvent.ALL_COLUMNS,TableModelEvent.UPDATE);
this.avisaSuscriptores(e);
}

A la hora de realizar el update, prefiero primero remover de la lista el elemento (persona) que se encuentra en el lugar indicado por el parametro fila, para despues realizar la acutalizacion.

Construyendo la tabla

Una vez creado el modelo de tabla que vamos a utilizar, solo resta crear la tabla.
Después de ver distintos códigos de cómo se crearon tablas y scrollpane, y luego se le asignaban restricciones, layouts y metodos etc, etc, encontré navegando la forma mas sencilla de crearla:
En el frame que vamos a utilizar, podemos arrastrar y soltar algún JScrollPane así lo ubicamos y le damos el tamaño que deseamos. Luego vamos al codigo y escrivimos:

MyModelo modelo =new MyModelo();
JTable tabla =new JTable(modelo);
JScrollPane jScrollPane1 =new JScrollPane(tabla);//este es el scroll creado por el ide y
//le modificamos el constructor pasandole como parametro la tabla

Sencillito no? y así, como por arte de magia tendremos una tabla. Eso si después si queremos, podemos agregar código para darle a nuestra tabla un comportamiento mas profesional.

Trabajando con los datos de la tabla

Si queremos cargar un dato de la tabla a una variable para que la podamos manejar directamente de la memoria podemos hacer uso del los eventos del Mouse o de algún botón. Se puede realizar código que cargue todos los datos o seleccionar uno… en fin las posibilidades son muchas.

En el caso de insertar la persona hacemos:

Personas p = new Personas(25425456,”Lopez”,”Juan”);
modelo.insertarPersona(p);

..y la persona se agregara al final de la tabla.
De forma similar trabajamos con el resto de los métodos del modelo.
Mas adelante, escribiré como definir el tamaño de las columnas, y las posibilidades de agregarle componentes a las celdas, imágenes, colores, etc.
Espero haber sido de ayuda, saludos y hasta la proxima.

miércoles, noviembre 15, 2006

Fechas under Java - Calendar, getInstance(), get(), set(), add(), compareTo()

La clase a utilizar será Calendar de java.util. Esta clase nos brinda información sobre todo lo que tenga que ver con el tiempo, es muy completa, las zonas horarias que utilizamos, y cualquier cosa que se nos pueda ocurrir.
Como es un clase abstracta, no puede ser instanciada, es decir que no tendrá un constructor típico “new Calendar()”, en ves de ello utilizaremos el método getInstance()

Calendar fecha= Calendar.getInstance();

En fecha quedaran almacenados los datos del sistema (hora, fecha) del momento en que fue creada, si pretendemos ver que tipos de datos maneja, podemos hacer uso del método toString()

System.out.println(fecha.toString());

Obteniendo y poniendo Fechas

Para asignar valore y obtenerlos utilizaremos los métodos get() y set(). Pero primero lo primero, las constantes que nos permiten setear son enteros por lo que deberemos guardarlos o poner enteros. Las agregaría acá pero con solo poner un “.” En su IDE favorito se desplegaran todas las que se imaginan y un poquito mas.

Comenzaremos por obtener los datos

//calendar.get(int campo);
Int hora = fecha.get(Calendar.HOUR);

Siempre deberemos utilizar el nombre de la clase un punto y la constante deseada. Las constantes más communes a utlilizar son HOUR, HOUR_OF_DAY, MINUTE, SECOND, DAY_OF_MONTH, MONTH, YEAR, DAY_OF_WEEK, DAY_OF_WEEK_IN_MONTH. Estas ultimas nos sirven para cuando queremos trabajar con los días de la semana como lunes, martes… etc. Nos devolverá un número que mas tarde podremos convertirlo en un String.

Poner los datos deseados
podemos poner un solo dato...
Int hora = 13;

//calendar.set(int campo,valor);
fecha.set(Calendar.HOUR_OF_DAY, hora);

o todos los que deseamos a la ves...
fecha.set(int años, int mes,int dia);
fecha.set(int año,
int mes,int dia,int hora_del_dia, int minutos)
fecha.set(
int año,int mes,int dia,int hora_del_dia, int minutos, int segundos);

Si vamos a trabajar con horas, debemos hacer la distinción ente HOUR y HOUR_OF_DAY, la primera nos mostrará la hora de 0-11 y la segunda de 0-23. Si vamos a trabajar con meses deberemos restarle uno, así por ejemplo noviembre será el mes 10.

Sumar a una Fecha

para sumarle a una variable de tipo Calendar podemos utilizar el método add(), aunque si se desea se puede utilizar el método roll().

//Calendar.add(int campo, int aumento)
hora.add(Calendar.HOUR_OF_DAY,2);

Así se incrementaran dos horas, a la hora de la instancia. Trabajo similar se puede realizar con cualquiera de las constantes.
El método roll() tiene dos formas:
El primero de ellos tiene un comportamiento similar al del metodo add() pero la diferencia yace en que se incrementara sin cambiar los campos superiores. Por ejemplo se incrementaran los minutos pero cuando se produzca un incremento en la hora, esta no cambiara a difrencia de add(). Y la llamada al metodo puede ser de dos formas:

//1) fecha.roll(int campo, int incremento);

El segundo es como un contador
//2) fecha.roll(int campo, boolean arriba);
Dependiendo del valor boolean se incrementara en uno hacia arriba o decrementara hacia abajo.

Compardando dos calendarios
El metodo a utilizar es compareTo(Calendar otro)

//Calendar.compareTo(Calendar otro_calendario)
Calendar hora1= Calendar.getInstance();
Calendar hora2=Calendar.getInstance();
hora2.add(Calendar.MINUTE,1);
int d =hora1.compareTo(hora2);

Nos devolverá -1 si hora1 es menor que hora2, 0 si son iguales, y 1 si el primero es mayor que el segundo.

Sacando diferencias entre calendarios

Yo en este caso utilice formulas matemáticas para sacar diferencias entre los calendarios, también se puede sacar las diferencias entre milisegundos, pero esas diferencias igualmente se deben convertir, es por ello que preferí crear mis propios métodos. Por ejemplo para sacar la diferencia en minutos entre una hora y otra en el mismo dia…

Int diferencia = (hora1.get(Calendar.HOUR_OF_DAY)*60+ hora1.get(Calendar.MINUTE)) -(hora2.get(Calendar.HOUR_OF_DAY)*60+ hora2.get(Calendar.MINUTE))

Y jugando con valores negativos y positivos.
Tan simple como lo visto es trabajar con calendarios. Espero haber ayudado.

Tecnicamente hablando...

Recorriendo Internet, under Java, me costo mucho recoger información en castellano, es por ello que empezare a escribir sobre las cosas que me costaron mas encontrar, este será mi aporte a
al conocimiento y a la evangelización de la iglesia de “Sun Java”.