|
![]() |
Eventos de Bajo Nivel y Semánticos |
Anterior | Siguiente |
Aunque el conjunto de eventos semánticos es
utilizado para propósitos diferentes que el conjunto de eventos de bajo nivel, desde el
punto de vista de la programación la diferencia es muy poca. La principal diferencia parece residir en la naturaleza del objeto evento que es pasado al controlador de eventos en el momento en que algo sucede. Utilizando la información del objeto evento, los eventos de bajo nivel pueden acceder al Componente específico que ha generado el evento, porque todas las clases de eventos de bajo nivel son subclases de la clase ComponentEvent. Una vez que la referencia a ese Componente está disponible, hay docenas de métodos de la clase Component que pueden ser invocados sobre el objeto, como getLocation(), getName(), getMaximumSize(), etc. Los eventos de tipo semántico, por otro lado, no son subclase de la clase ComponentEvent, sino que son subclase de la superclase de ComponentEvent, es decir, son hermanos de ComponentEvent. Al no ser subclase de ComponentEvent, los objetos evento pasados a controladores de eventos semánticos proporcionan un método para obtener una referencia al objeto que ha generado el evento y, por lo tanto, no pueden invocar los métodos de la clase Component sobre ese objeto. Que lo anterior tenga importancia o no depende de las necesidades del programa. Por ejemplo, si se necesita determinar la posición del objeto que ha generado un evento, se puede hacer procesando un evento de bajo nivel y, probablemente, no se pueda determinar esa posición procesando un evento semántico; y se indica probablemente, porque nunca se puede decir nunca, si no queremos que alguien demuestre que estamos equivocados. Quitando la posibilidad de acceder al objeto que ha generado el evento, el nombre del objeto está disponible tanto para los eventos de bajo nivel como para los eventos semánticos. En ambos casos, el nombre del objeto está encapsulado en el objeto evento pasado como parámetro y puede extraerse y comprobarse utilizando métodos de la clase String. En muchas ocasiones, el saber el nombre del objeto es suficiente para conseguir el resultado apetecido. El programa java1105.java, muestra algunas de las capacidades de los eventos de bajo nivel. Sobre un objeto Frame se coloca en la parte superior un objeto Button y en al inferior un objeto TextField, tal como muestra la figura siguiente, que corresponde a la captura de la ventana resultante de la ejecución del ejemplo. Un objeto MouseListener es instanciado y registrado para monitorizar eventos de bajo nivel mousePressed() sobre los tres objetos. Cuando se produce un evento de este tipo, el objeto receptor obtiene y presenta información sobre el objeto que ha generado el evento. Aunque esto es lo único que hace la aplicación, todos los métodos de la clase Component están disponibles para realizar cualquier otro tipo de acciones. También hay un objeto WindowListener que es instanciado y registrado para terminar el programa cuando el usuario decida cerrar el objeto Frame. En el ejemplo java1106.java, se incluyen controladores de bajo nivel y semánticos para los mismos tres componentes del programa anterior. Como antes, se coloca un objeto Button y un objeto TextField sobre un objeto Frame. El controlador de nivel semántico trata los eventos Action y el controlador de bajo nivel trata los eventos mousePressed y los eventos Focus sobre los mismos componentes. A continuación se verán en detalle los eventos y objetos que intervienen en la aplicación. En Java, cuando se dice que un Componente tiene el foco, significa que las entradas de teclado se dirigen a ese Componente. Hay muchas razones por las que pasa el foco de un Componente a otro, y cuando esto sucede, se genera un evento focusLost() en el Componente que pierde el foco y el que recibe el foco, genera un evento focusGained(). Es base a esta pequeña explicación, es fácil comprender que haya muchos tipos de Componentes que pueden generar este tipo de eventos, ya que cualquier Componente que pueda ganar el foco también podrá perderlo y generará esos eventos. Hay algunos Componentes como son los Botones y los Campos de Texto, que ganan el foco automáticamente cuando se pulsa sobre ellos con el ratón. En otros Componentes, sin embargo, esto no ocurre, como por ejemplo, en las Etiquetas, aunque estos Componentes pueden ganar el foco si lo solicitan. Un evento Action puede ser generado por muchos Componentes. Por ejemplo, pulsando con el ratón o pulsando la tecla Retorno cuando el foco está sobre un Campo de Texto, se generará un evento de este tipo. La terminología deriva de que las acciones de usuario generan acciones hacia el programa para realizar algo específico, en función de la naturaleza del Componente del que ha surgido el mensaje. Por ejemplo, si un Botón tiene la etiqueta "Salir" y es pulsado con el ratón, esto significa que el usuario está esperando que el programa realice alguna acción que el interpreta como una salida del programa. En este ejemplo, un objeto ActionListener es instanciado y registrado para monitorizar de forma semántica eventos de tipo actionPerformed() sobre el Botón y el Campo de Texto. Cuando se genera un evento de este tipo, hay cierta información acerca de este evento que es encapsulada en un objeto que se le pasa al método actionPerformed() del objeto Receptor. La documentación oficial del JDK le llama a esto command name. A esta información puede accederse a través de la invocación al método getActionCommand() sobre el objeto. En este ejemplo, se accede al command name y se presenta en la pantalla. El nombre del comando asociado con el Botón es simplemente el texto o etiqueta que figura sobre el botón. El nombre del comando asociado al Campo de Texto es el texto actual que contiene el campo. Esta información puede ser utilizada por de diferente forma por los Componentes; por ejemplo, puede ser utilizada para distinguir entre varios botones si no se permite cambiar sus etiquetas durante la ejecución del programa. También se puede utilizar para capturar la entrada del usuario desde un objeto Campo de Texto. El objeto de tipo ActionEvent que se pasa al método actionPerformed() también incluye el nombre del componente, que en este ejemplo es utilizado en comparaciones para identificar el Componente que está generando el evento. Una forma de hacer esto es utilizar el método indexOf() de la clase String, para determinar si un Componente determinado se encuentra incluido en un objeto específico. En este programa, cada vez que se invoca al método actionPerformed(), el código en el cuerpo del método utiliza precisamente la llamada al método indexOf() para identificar el Componente que ha generado el evento y presenta un mensaje en pantalla indicando el nombre del componente, su command name. Se instancia un objeto FocusListener y también se registra, para monitorizar a bajo nivel los eventos focusGained() y focusLost(), sobre el botón y el campo de texto. Cuando se produce un evento focusGained(), se presenta en pantalla un mensaje indicando el objeto que ha ganado el foco. De la misma forma, cuando ocurre un evento focusLost(), también se presenta un mensaje que indica el objeto que ha perdido el foco. El objeto que gana o pierde el foco se identifica a través de comprobaciones condicionales sobre el objeto FocusEvent pasado como parámetro, del mismo modo que se hace con el objeto ActionEvent utilizado en los eventos de acción. Un objeto MouseListener es instanciado y registrado para monitorizar a bajo nivel eventos de tipo mousePressed() sobre los tres objetos que conforman el interfaz. No se controlan otros de los muchos eventos que se producen por mantener una cierta simplicidad en el ejemplo. El objeto MouseListener distingue entre los tres objetos: Frame, Button y TextField, en base al nombre del componente que se asigna a cada objeto en el momento de su instanciación. Si el programador no asigna nombres a los Componentes cuando son instanciados, el sistema le asignara nombres por defecto. Estos nombres que asigna el sistema tienen el formato frame0, frame1, frame2, etc., con la parte principal del nombre indicando el tipo de Componente y el dígito final se va asignando en el mismo orden en que se van instanciando los objetos. En este ejemplo, se utiliza el método indexOf() sobre el objeto MouseEvent para determinar el nombre del componente. Esto es un poco menos complejo que el método utilizado en ejemplos anteriores, basado en recuperar el objeto e invocar su método getName(). Cuando se produce un evento mousePressed() sobre cualquiera de los tres objetos visuales, el objeto MouseListener presenta un mensaje en pantalla identificando el objeto que ha generado el evento. Por último, para terminar la descomposición del programa, un objeto WindowListener es instanciado y registrado para terminar la ejecución de la aplicación cuando el usuario cierra el objeto Frame. La salida por pantalla que se produce tras algunas acciones del usuario, es la que se reproduce en las siguientes secuencias.
Capturado mousePressed sobre el objeto Frame
Capturado mousePressed sobre el objeto CampoTexto Capturado focusLost sobre el objeto Boton Capturado focusGained sobre el objeto CampoTexto
evt.getActionCommand() = Cadena Inicial Capturado actionPerformed sobre el objeto CampoTexto
Capturado mousePressed sobre el objeto Boton Capturado focusLost sobre el objeto CampoTexto Capturado focusGained sobre el objeto Boton evt.getActionCommand() = Púlsame Capturado actionPerformed sobre el objeto Boton Para mantener la simplicidad, la respuesta a los eventos en este programa se limita a presentar información en pantalla. Obviamente, cuando en flujo de ejecución se encuentra dentro del código que controla el evento, el programador puede implementar respuestas diferentes. También hay que hacer notar al lector, que en el ejemplo se da el hecho de que una sola acción del usuario origina varios tipos diferentes de eventos. |
|