domingo, 20 de abril de 2014

Actualizar/Insertar texto a un TextArea (Componente) desde otra Clase



En ocaciones si se quiere como muchos dirían "Elegante" en el código es necesario hacer diferentes clases para que sea más atendible y sea óptimo el código, pero el ser "Elegante" nos trae algunos problemas.

Si tenemos tres clases Principal.java, Ventana.java, Analisis.java. En donde:

Principal.java
Tenemos simplemente un main que tiene un objeto de tipo ventana y mostramos la ventana con ven.setVisible(true) y demás cosas como hacer que la ventana se vea más bonita.

Ventana.java
Tenemos toda la lógica de una ventana común en java es decir el tamaño, nombre, botones, textAreas, textFields, tablas, etc., nos sirven para mostrar los que hace nuestro programa.

Analisis.java
Aquí esta la lógica del programa es decir lo que realmente hace nuestro programa.

En este caso lo lógico es hacer lo siguiente si desde la clase Analisis.java queremos poner en textField, tabla o algo así alguna información para el usuario porque el usuario así lo requiera, lo que haríamos sería:


COMO NO HACERLO
public class Analisis{
//todo lo necesario

public void metodoHaceAlgo(){
//todo lo que haga

//quiero mandar a un JTextArea algo (TextArea esta definido en Ventana.java)
Ventana ven2 = new Ventana();
ven2.setAlTextArea("mi_mensaje"); 

}
}

public Class Ventana  extends JFrame{
//todo lo que lleve

JTextArea  jta1 = new JTextArea();

//lo que sea...

public setAlTextArea(String algo){
System.out.println(algo);
jta1.setText(jta1.getText() + algo);  //lo único que hace es poner lo que le mandes al TextArea
}

}

public class Principal{

public static void main( String args[] ){
//lo que sea

Ventana ven1 =  new Ventana();

ven1.setVisible(true);
//demás cosas

}//cierra main
}

CON LA LÓGICA ANTERIOR QUE PUEDE SER LA MÁS OBVIA EL PROGRAMA SIMPLEMENTE NO FUNCIONA, aunque si imprimiría el valor de "algo" en consola.

COMO HACER LO ANTERIOR CORRECTAMENTE
Sin duda hay otra forma quizás más simple de hacerlo, en esta ocasión yo les presento una no muy difícil de entender.

La solución se basa (PUEDE SERVIR PARA OTRAS COSAS) separar las cosas aunque se puede hacer con las mismas tres clases, pero para ser más "elegantes", entonces:

  -  Agregamos una clase más llamada panelContext que extiende de JPanel y su función es prácticamente pasar todo lo que teníamos en Ventana.java a su vez Ventana.java solo nos prestara un frame en donde pegaremos todo lo que tenemos en el Panel, esto es para que todo mundo accede al panel y los cambios se vean reflejados en el Frame.

- Hacemos que nuestra nueva clase sea un Singleton (Ir al final para ver que es)


Las clases quedarían

public class PanelContext extends JPanel{
 private static PanelContext pnlCtx = new PanelContext();

   public static PanelContext getInstance() {
            return pnlCtx;
    }

//constructores y todo lo demás


}

Para usar la misma instancia debmos usar
PanelContext pnlCtx =  PanelContext.getInstance();

de este modo Analisis.java quedaría

public class Analisis{
//todo lo necesario

public void metodoHaceAlgo(){
//todo lo que haga

//quiero mandar a un JTextArea algo (TextArea esta definido en Ventana.java)

pnlCtx.setAlTextArea("mi_mensaje"); 

}
}

En Ventana.java quedaría 

public class Ventana Extends JFrame{

public Ventana(){
        PanelContext pnlCtx =  PanelContext.getInstance();
        this.getContentPane().add(PanelContext.getInstance());

//**


//todo lo que haga falta

}

}

**Si por alguna razón en el constructor (o un método que se llame en el constructor que tenga eso) tenemos lo siguiente HAY QUE QUITARLO
this.getContentPane().setLayout( null );

Ya que lo que se esta haciendo con las dos lineas que pusimos es decirle a la ventana que tome lo que hay en el Panel que creamos y de esta forma podemos poner en un Frame un Panel.


Y de esta forma es como se resuelve, también es bueno decir que el anterior no funcionaba porque se estaban haciendo instancias diferentes y por lo tanto se reflejaba en otra que ni siquiera se mostraba.


También puede servir
Cuando tenemos varios clientes que quieren instanciar a algo, lo único que tienes que hacer es obligarlos a que usen la misma instancia



Un Singleton 
Según la enciclopedia más consultada del mundo (Wikipedia) es:
El patrón de diseño singleton (instancia única) está diseñado para restringir la creación de objetos pertenecientes a una clase o el valor de un tipo a un único objeto.
Su intención consiste en garantizar que una clase sólo tenga una instancia y proporcionar un punto de acceso global a ella.
El patrón singleton se implementa creando en nuestra clase un método que crea una instancia del objeto sólo si todavía no existe alguna. Para asegurar que la clase no puede ser instanciada nuevamente se regula el alcance del constructor (con atributos como protegido o privado).
La instrumentación del patrón puede ser delicada en programas con múltiples hilos de ejecución. Si dos hilos de ejecución intentan crear la instancia al mismo tiempo y esta no existe todavía, sólo uno de ellos debe lograr crear el objeto. La solución clásica para este problema es utilizar exclusión mutua en el método de creación de la clase que implementa el patrón.

EN pocas palabras hace que solo tengamos una Instancia pues.
http://es.wikipedia.org/wiki/Singleton