Debo decir que, sin duda, mi lenguaje favorito es Java y disfruto mucho aprender cosas nuevas sobre su uso y las herramientas que tengo a mi disposición. La creación de eventos en Java es un tema que a mucha gente le gustaría dominar pero que no es tan fácil de comprender si somos principiantes o aficionados, como es mi caso.
Pero, ¿qué son los eventos en Java?
La definición de evento, según el diccionario de la Real Academia Española dice:
«Suceso importante y programado, de índole social, académica, artística o deportiva.«
También encontramos la definición:
«Cosa que sucede.»
Nos quedamos con la segunda, ya que es lo que más se adapta a nuestro ámbito de la programación. Cosa que sucede.
Supongamos que tenemos un programa donde se hace necesario monitorear cierta condición en particular. Digamos que tenemos una variable y queremos determinar cuando sea que dicha variable sufra alguna modificación. O que queremos indicarle a un software en específico cuando sea que haya pasado una hora después del inicio de su ejecución. Lo que necesitaríamos es crear un evento que ejecute una acción cuando sea que algo suceda. Una cosa que sucede dispara un método en específico con las acciones que deseamos llevar a cabo ante dicha acción.
Cuando nosotros creamos una interface gráfica en Netbeans nos aparece una lista de eventos de los cuales podemos escoger. Por ejemplo, en un Frame tenemos la siguiente lista de eventos:
Si nos adentramos en alguno de los menús desplegables, por ejemplo Mouse, veremos los eventos que se desencadenan cuando algo sucede con el Mouse.
Vemos por ejemplo que el evento mouseClicked desencadenará una serie de instrucciones preestablecidas por nosotros cuando sea que se haga clic sobre el JFrame. Cuando utilizamos botones, al hacer click sobre ellos desencadenamos el evento ActionPerformed y de esa forma le damos funcionalidad a nuestras interfaces. Lo que haré en este post es mostrar al usuario como crear eventos más allá de aquellos que podemos utilizar con nuestras interfaces gráficas.
Preparando nuestro proyecto
Hace unos días publiqué un post sobre Listas multidimensionales en Java. Voy a tomar una clase que utilicé en dicho ejemplo y la voy a traer a este post.
Para explicar la creación de eventos en Java necesitaremos un proyecto para hacer pruebas. Vamos a Netbeans y creamos un proyecto al que vamos a llamar eventTest. Agregamos una clase a la que llamamos Empresa.
En la clase Empresa, colocamos el siguiente código que podemos encontrar en el post de Listas multidimensionales.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
package eventtest; public class Empresa { private String ID; private String Nombre; private String Apellido; private int Edad; private String Empresa; public Empresa(String _ID, String _Nombre, String _Apellido, int _Edad, String _Empresa) { ID=_ID; Name=_Nombre; Apellido=_Apellido; Edad=_Edad; Empresa=_Empresa; } public String getID() { return ID; } public String getName() { return Nombre; } public String getLastName() { return Apellido; } public int getAge() { return Edad; } public String getBuiness() { return Empresa; } public void setID(String _ID) { ID = _ID; } public void setName(String _Nombre) { Nombre = _Nombre; } public void setLastName(String _Apellido) { Apellido = _Apellido; } public void setAge(int _Edad) { Edad = _Edad; } public void setBusiness(String _Empresa) { Empresa = _Empresa; } } |
La clase empresa contiene los getters y setters para el manejo de las variables que pertenecen a la clase. En nuestra clase principal vamos a crear una instancia de la clase Empresa.
1 2 3 4 5 6 7 8 9 10 |
package eventtest; public class EventTest { public static void main(String[] args) { Empresa empresa = new Empresa("1-234-567", "Antony", "García", 22, "Panama Hitek"); } } |
Al crear la instancia necesitamos establecer los valores iniciales para el objeto que creamos, en este caso, uno que me representa a mi, Antony García, con información personal y de mi empresa.
Al guardar dicha información en un objeto, puedo llamarla cuando yo quiera o lo necesite. Hagamos un pequeño ensayo:
Vemos que en la consola nos aparece la información que introduje como parámetros iniciales del objeto empresa. Si hacemos mención del objeto empresa, nos aparecerán los métodos disponibles para este objeto, que en este caso son los getters y setters que definimos en la clase Empresa.
El evento que vamos a crear trabajará con los setters. Cuando sea que se modifique alguno de estos parámetros dispararemos un evento.
El EventObject
Debemos crear una clase que contenga todo lo relacionado a los eventos que deseamos crear. Esta clase debe extender a EventObject.
En nuestro proyecto creamos una clase que llamaremos changeEvent. El código de esta clase es el siguiente:
1 2 3 4 5 6 7 8 9 10 11 |
package eventtest; import java.util.EventObject; public class changeEvent extends EventObject { Empresa empresa; public changeEvent(Object source, Empresa _empresa) { super(source); empresa = _empresa; } } |
Nuestro proyecto ahora debe lucir así:
La interfaz EventListener
Esta es la definición propia de los eventos. En ella se definen los métodos abstractos. Pero, ¿qué son métodos abstractos? Veamos.
En nuestro proyecto vamos a crear una clase que llamaremos changeEventListener. Dentro colocamos el siguiente código:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
package eventtest; import java.util.EventListener; public interface changeEventListener extends EventListener { public abstract void onIDChange(changeEvent ev); public abstract void onNameChange(changeEvent ev); public abstract void onLastNameChange(changeEvent ev); public abstract void onAgeChange(changeEvent ev); public abstract void onBusinessChange(changeEvent ev); } |
Estos son los métodos que se van a disparar cuando suceda algún cambio en alguno de los datos que recoge la clase Empresa. Por ejemplo, sin una vez establecemos el nombre y luego queremos cambiarlo, se va a disparar ejecutar el método onNameChange. Nuestro proyecto ahora debe lucir asi:
Ahora en nuestra clase principal podemos crear un objeto de la interface changeEventListener. Veamos lo que sucede:
Nos pide que implementemos los métodos abstractos. Al hacer clic en la sugerencia nos aparecen todos los métodos que ya declaramos en la interfaz changeEventListener.
Ahora necesitamos establecer las acciones que se ejecutarán cuando se produzca cada evento.
Los cambios que quedan por hacer los hacemos en la clase Empresa que es donde se instalarán las instrucciones para disparar los eventos.
Creamos una variable donde guardaremos los listeners o «escuchadores». Estos son los manipuladores de los eventos. En el método Empresa de la clase empresa, colocamos lo siguiente:
1 |
listeners = new ArrayList(); |
Lo que hemos hecho es crear un array que guarde los manejadores. Al iniciar la clase Empresa, iniciamos el ArrayList. Ahora hay que crear un método para agregar los manejadores al ArrayList.
1 2 3 |
public void addEventListener(changeEventListener listener) { listeners.add(listener); } |
Ahora creamos los métodos que van a disparar cada evento. A continuación los métodos «disparadores»:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
private void triggerNameEvent() { ListIterator li = listeners.listIterator(); while (li.hasNext()) { changeEventListener listener = (changeEventListener) li.next(); changeEvent readerEvObj = new changeEvent(this, this); (listener).onNameChange(readerEvObj); } } private void triggerLastNameEvent() { ListIterator li = listeners.listIterator(); while (li.hasNext()) { changeEventListener listener = (changeEventListener) li.next(); changeEvent readerEvObj = new changeEvent(this, this); (listener).onLastNameChange(readerEvObj); } } private void triggerIDEvent() { ListIterator li = listeners.listIterator(); while (li.hasNext()) { changeEventListener listener = (changeEventListener) li.next(); changeEvent readerEvObj = new changeEvent(this, this); (listener).onIDChange(readerEvObj); } } private void triggerAgeEvent() { ListIterator li = listeners.listIterator(); while (li.hasNext()) { changeEventListener listener = (changeEventListener) li.next(); changeEvent readerEvObj = new changeEvent(this, this); (listener).onAgeChange(readerEvObj); } } private void triggerBusinessEvent() { ListIterator li = listeners.listIterator(); while (li.hasNext()) { changeEventListener listener = (changeEventListener) li.next(); changeEvent readerEvObj = new changeEvent(this, this); (listener).onBusinessChange(readerEvObj); } } |
Nuestro código debe lucir así:
Nosotros queremos que cuando se produzca algún cambio en alguna variable, se dispare el evento. Así que cuando se invoque algún setter, ahí desencadenamos el método que corresponda.
Al final, nuestra clase Empresa quedaría así:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
package eventtest; import java.util.ArrayList; import java.util.ListIterator; public class Empresa { private String ID; private String Nombre; private String Apellido; private int Edad; private String Empresa; private static ArrayList listeners; public Empresa(String _ID, String _Nombre, String _Apellido, int _Edad, String _Empresa) { ID = _ID; Nombre = _Nombre; Apellido = _Apellido; Edad = _Edad; Empresa = _Empresa; listeners = new ArrayList(); } public void addEventListener(changeEventListener listener) { listeners.add(listener); } private void triggerNameEvent() { ListIterator li = listeners.listIterator(); while (li.hasNext()) { changeEventListener listener = (changeEventListener) li.next(); changeEvent readerEvObj = new changeEvent(this, this); (listener).onNameChange(readerEvObj); } } private void triggerLastNameEvent() { ListIterator li = listeners.listIterator(); while (li.hasNext()) { changeEventListener listener = (changeEventListener) li.next(); changeEvent readerEvObj = new changeEvent(this, this); (listener).onLastNameChange(readerEvObj); } } private void triggerIDEvent() { ListIterator li = listeners.listIterator(); while (li.hasNext()) { changeEventListener listener = (changeEventListener) li.next(); changeEvent readerEvObj = new changeEvent(this, this); (listener).onIDChange(readerEvObj); } } private void triggerAgeEvent() { ListIterator li = listeners.listIterator(); while (li.hasNext()) { changeEventListener listener = (changeEventListener) li.next(); changeEvent readerEvObj = new changeEvent(this, this); (listener).onAgeChange(readerEvObj); } } private void triggerBusinessEvent() { ListIterator li = listeners.listIterator(); while (li.hasNext()) { changeEventListener listener = (changeEventListener) li.next(); changeEvent readerEvObj = new changeEvent(this, this); (listener).onBusinessChange(readerEvObj); } } public String getID() { return ID; } public String getName() { return Nombre; } public String getLastName() { return Apellido; } public int getAge() { return Edad; } public String getBuiness() { return Empresa; } public void setID(String _ID) { ID = _ID; this.triggerIDEvent(); } public void setName(String _Nombre) { Nombre = _Nombre; this.triggerNameEvent(); } public void setLastName(String _Apellido) { Apellido = _Apellido; this.triggerLastNameEvent(); } public void setAge(int _Edad) { Edad = _Edad; this.triggerAgeEvent(); } public void setBusiness(String _Empresa) { Empresa = _Empresa; this.triggerBusinessEvent(); } } |
Por último, en nuestra clase principal agregamos el manejador. También agregamos a propósito una instrucción de cambiar un el la información del usuario. En los métodos abstractos colocaré instrucciones para imprimir en la consola un mensaje cada vez que se haga un cambio utilizando los setters. Nuestra clase principal quedaría así:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
package eventtest; public class EventTest { static changeEventListener events = new changeEventListener() { //Lo que va a suceder cada vez que se produzca un evento determinado @Override public void onIDChange(changeEvent ev) { System.out.println("Se cambió el ID"); } @Override public void onNameChange(changeEvent ev) { System.out.println("Se cambió el nombre"); } @Override public void onLastNameChange(changeEvent ev) { System.out.println("Se cambió el apellido"); } @Override public void onAgeChange(changeEvent ev) { System.out.println("Se cambió la edad"); } @Override public void onBusinessChange(changeEvent ev) { System.out.println("Se cambió el nombre de la empresa"); } }; public static void main(String[] args) { Empresa empresa = new Empresa("1-234-567", "Antony", "García", 22, "Panama Hitek"); empresa.addEventListener(events); //Cambio los valores iniciales por unos nuevos empresa.setID("7-654-321"); empresa.setName("Kiara"); empresa.setLastName("Navarro"); empresa.setAge(24); } } |
Al correr nuestra aplicación, el resultado en consola es el siguiente:
Vemos que establecimos los valores iniciales, es decir, Antony García, con ID 1-234-567, edad 22 años y la empresa Panama Hitek. Al cambiar el nombre establecido en el objeto, el método abstracto onNameChange se ejecuta. La instrucción: imprimir el mensaje «Se cambió el nombre» en la consola. Lo mismo sucederá al cambiar cada dato.
Con esto podemos tener una idea muy general sobre lo que necesitamos para la creación de eventos en Java. Una clase que funcione como interfaz, una clase que extienda EventObject y establecer los métodos de disparo en la clase donde se produce los eventos que queremos disparar.
Los archivos de este proyecto pueden ser descargados gratuitamente desde nuestro repositorio en Github.
Esto es todo por ahora. Saludos.