Creación y jerarquía de eventos

Chano Vera

Desarrollador
26 septiembre, 2023

Una de las principales funciones de los programas, es darle respuesta al usuario cuando efectúa ciertas acciones como:

  • Presionar un botón.
  • Seleccionar un elemento.
  • Mover el ratón.

Para llevar estas acciones, puedes emplear los eventos.

Un usuario, al interactuar con su equipo, lo hace a través de la interfaz gráfica de un programa. Esta interfaz puede ser:

  • Un botón.
  • Selectores.
  • Campos de entrada o texto.
  • Otros.

Cuando el usuario realiza alguna de estas acciones, el programa internamente llama a un método, el cual efectúa cierta lógica de programación que puede o no, otorgar una respuesta al usuario. En Java, a esto se le conoce como evento.

La dinámica de trabajo con un evento inicia con el objeto fuente, pero éste no actúa, sino que delega la acción al objeto oyente, que es el encargado de aplicar la lógica de programación correspondiente.

Ejemplo de evento delegando su ejecución al objeto oyente (listener)

Tipos de eventos

Según la acción que realice el usuario y el tipo de componente que se esté utilizando, el sistema puede devolver uno o más eventos.

El objeto fuente genera el o los eventos y el objeto oyente se encarga de gestionarlos.

Los eventos se pueden clasificar en dos tipos:

Evento de bajo nivel

Características:

  • Representan los cambios en el sistema, como: la posición, el aumento o decremento en el tamaño y obtención o pérdida del foco de la interacción.
  • Además de las acciones efectuadas por el usuario, tales como: el uso del teclado o del ratón.

Nota: La pulsación de una tecla, por ejemplo, genera tres eventos: uno cuando se pulsa, otro cuando se suelta y el de la propia escritura.

ComponentEventCambios en el tamaño, posición o visibilidad de un componenteSe implementa la interfaz ComponentListener
FocusEventCambios de foco (capacidad del componente de recibir texto)Se implementa con la interfaz FocusListener
KeyEventOperación con el tecladoSe implementa con la interfaz KeyListener
MouseEventOperación con los botones y el movimiento del ratónSe implementa la interfaz MouseListener
WindowEventCambio de estado en una ventanaSe implementa con la interfaz WindowListener
AncestorEventCambio en la composición, visibilidad o posición de un elemento superiorSe implementa con la interfaz AncestorListener
Bajo nivel

Evento de alto nivel

Características:

  • También llamados eventos semánticos.
  • Capturan el significado de la acción del usuario.
  • No están relacionados con una clase específica de componente.
  • Son aplicables para todos los componentes que tengan una forma de trabajo similar.
  • Estos no necesariamente tienen que generar el evento de la misma forma.
ActionEventRealización de una acción específica asociada al componenteSe implementa con la interfaz ActionListener
ChangeEventCambio en el estado del componenteSe implementa con la interfaz ChangeListener
ItemEventElemento seleccionado o deseleccionadoSe implementa con la interfaz ItemListener
CaretEventCambio en la posición del cursor de inserción en un componente que gestiona textoSe implementa con la interfaz CaretListener
ListSelectionEventCambio en la selección actual de una listaSe implementa con la interfaz ListSelectionListener
Alto nivel

Creación de eventos

Existen varias formas de implementar un evento en Java, con éstas, puedes conocer qué acciones realizan los usuarios sobre las aplicaciones.

Clases adaptadoras

La mayoría de las interfaces que Java proporciona están diseñadas para responder a varios tipos de eventos, para ello, cuentan con más de un método.

Revisa el siguiente ejemplo:

La interfaz que responde a las acciones del ratón (MouseInputListener) tiene siete métodos que puedes implementar

Cuando trabajas con este tipo de interfaces, necesariamente llamas a todos sus métodos, aunque no los requieras, por lo que se quedarán varios los que no ocupes.

Por lo anterior, Java proporciona una alternativa:

  • Java tiene a su disposición un conjunto de clases adaptadoras abstractas, las cuales sirven para simplificar la escritura de oyentes, e incluyen las definiciones vacías de los métodos.
  • De esta manera, un oyente se puede crear al momento de especializar un adaptador, además de que se pone en funcionamiento solo el método que interese.
  • En Java se incluye una clase adaptadora por cada interfaz oyente que tiene más de un método.

Estas clases se nombran Adapter.

Puedes ver la clase EventMouse, en la que se implementa la interfaz MouseInputListener, además, están agregados los métodos que contiene dicha interfaz.

class EventMouse implements MouseInputListener {

    @override
    public void mouseClicked(MouseEvent e) {}

    @override
    public void mousePressed(MouseEvent e) {}

    @override
    public void mouseReleased(MouseEvent e) {}

    @override
    public void mouseEntered(MouseEvent e) {}

    @override
    public void mouseExited(MouseEvent e) {}

    @override
    public void mouseDragged(MouseEvent e) {}

    @override
    public void mouseMoved(MouseEvent e) {}
}

Se encuentra la misma clase, pero extendida a la clase MouseInputAdapter, que permite utilizar solo los métodos necesarios.

public class adapterMouse extends MouseInputAdapter{

    @override
    public void mouseClicked(mouseEvent e) {
        // code
    }

}

Creación de eventos

Para que apliques los eventos a los diferentes elementos de la interfaz en este programa, agrega esos eventos a través de alguno de los métodos que provee Java.

Escucha de un botón.

boton.addActionListener(new ActionListener() {
    
    @override
    public void actionPerformed(ActionEvent ae) {
        // código
    }
});

Existen tres formas con las que puedes agregar eventos a los diferentes elementos de una interfaz, estos son:

  • Clase anónima.
  • Clase anidada.
  • Implementación de Listener en clase.

Clase anónima

Es la que se puede implementar sin asignarle un nombre, por lo que no vuelve a ser referenciada.

La sintaxis para su creación es:

new NombreClaseAnonima() {
    /* Definición de la clase anónima */
}

Estas clases son utilizadas cuando se necesita clases ligeras que funcionen como parámetros y, por lo general, implementan una interfaz.

JButton button = new JButton("Botón");
button.addActionListener(new ActionListener() {
    @override
    public void actionPerformed(ActionEvent ae) {
        // método que se ejecutará cuando se presione el botón
    }
});

Se tiene un botón al que se le agregó un evento mediante el método addActionListener; como argumento recibe una clase anónima, la cual se encarga de ejecutar el evento cuando se presiona el botón.

Clase anidada

Es la que se define como miembro de otra. Esto se hace con el propósito de agrupar clases que solo serán utilizadas dentro de una clase.

La forma para declararlas es la siguiente:

public class ClasePrincipal {
    // Código de la clase principal

    private class claseAnidada {
        // Código de la clase anidada
    }
}

Nota:

Este tipo de clases te permite implementar diferentes tipos de eventos a los que puedes acceder para su registro en los escucha de los componentes de la interfaz.

Observa que en el siguiente ejemplo se agregó una clase anidada, la cual controlará el evento del botón.

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;

public class EventButton extends Frame {
    EventButton() {
        // Métodos básicos para la creación de una ventana, los provee la clase JFrame
        setTitle("Evento del botón");
        setSize(500,500);
        setLayout(null);
        
        // Creación y ubicación del botón
        JButton button = new Button("Presionar");
        button.setBounds(100, 100, 100, 50);

        // Instancia de la clase anidada y evento relacionado con el botón creado
        EventButtonListener eventButtonListener = new EventButtonListener();
        button.addActionListener(eventButtonListener);

        // Agrega el botón a la ventana
        getContentPane().add(button);

        // Métodos básicos para la creación de una ventana, los provee la clase JFrame
        setVisible(true);
    }

    // Método principal de ejecución
    public static void main(String[] args) {
        EventButton e = new EventButton();
    }

    // Instancia de la clase anidada y evento relacionado con el botón creado
    public class EventButtonListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("actionPerformed");
        }
    }
}

Implementación de Listener en clase

Otra forma de implementar interfaces para el registro de eventos es usar la misma clase, pero como Listener.

public class NombreClase implements NombreInterfaz {

    @Override
    public void actionPerformed(ActionEvent e) {
        // código
    }
}

El trabajar de esta manera, implica que los métodos a sobrescribir queden en el mismo nivel que el resto del código.

Debido a esto, no es una opción muy recomendable, ya que la capa de presentación y lógica terminan combinándose dentro de la misma clase.

En este ejemplo la funcionalidad del botón se encuentra sobre la misma clase.

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.swing.JButton;
import java.swing.JFrame;

public class EventButton extends JFrame implements ActionListener {
    EventButon() {
        // Métodos básicos para la creación de una ventana, los provee la clase JFrame
        setTitle("Evento del botón");
        setSize(500,500);
        setLayout(null);
        
        // Creación y ubicación del botón
        JButton button = new Button("Presionar");
        button.setBounds(100, 100, 100, 50);
        
        // evento relacionado con el botón
        button.addActionListener(this);

        // Agrega el botón a la ventana
        getContentPane().add(button);

        // Métodos básicos para la creación de una ventana, los provee la clase JFrame
        setVisible(true);
    }

    // Método principal de ejecución
    public static void main(String[] args) {
        EventButton e = new EventButton();
    }

    // evento relacionado con el botón
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("actionPerformed");
    }
}

Cuestionario

¿Cuáles son los eventos de bajo nivel?

ComponentEvent, FocusEvent, KeyEvent, MouseEvent, WindowEvent, AncestorEvent.

¿Qué objeto es el encargado de ejecutar la lógica de programación de un evento?

El objeto oyente.

¿Qué son los eventos de bajo nivel?

Son aquellos eventos que no están relacionados con una clase específica de componente. Son aplicables a todos los componentes con un comportamiento similar.

¿Cuáles son los eventos de alto nivel?

Son aquellos que no están relacionados con una clase específica de componente, siendo aplicables a todos los componentes con un comportamiento similar. ActionEvent, ChangeEvent, ItemEvent, CaretEvent, ListSelectionEvent.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *