Discussion:
Prioridad en la gestión de eventos
(demasiado antiguo para responder)
Ricardo Palomares Martinez
2007-04-10 18:57:19 UTC
Permalink
Buenas:

Tengo un problema con el orden en el que se ejecutan algunos event
listeners. Tengo un JInternalFrame (una ventana en una aplicación MDI,
vamos) con un aspecto similar al del explorador de archivos de
Windows, con un JTree en la parte izquierda con carpetas, y un panel
en la derecha con un JTextField para editar una propiedad del objeto
subyacente en el nodo seleccionado en el JTree.

Así que podría tener lugar la siguiente secuencia de acciones:

- Se hace clic en la izquierda para elegir una carpeta
- Se dispara un evento TreeValueChanged y el listener de éste debe
actualizar el contenido en el panel con datos que pertenecen al nodo
(carpeta) recién seleccionado del árbol
- Se hace clic en el JTextField en la derecha, y se introduce un valor
- Al salir del JTextField (y perder éste el foco), se dispara un
evento FocusLost, y el listener correspondiente debe obtener el texto
del JTextField y actualizarlo en el objeto subyacente del nodo
seleccionado del árbol

Esto funciona bien si salgo del campo pulsando [Tab] (lo que me lleva
a un JButton que hay debajo del campo de texto). Mi problema surge si,
mientras tengo el foco en el campo de texto, hago clic en otro nodo
del árbol. En este caso, TreeValueChanged se ejecuta *antes* de
LocusFost (lo cual no encuentro lógico; primero se pierde el foco del
campo de texto y sólo entonces puede cambiar el valor del nodo
seleccionado en el árbol, EMO).

Por más que busco, no he podido encontrar ningún documento que indique
la prioridad con la que se ejecutan los eventos. He buscado este mismo
problema en Internet, en los tutoriales de Java, en los archivos de
foros y listas de correo, y en la documentación de JavaHispano.org
(*), y no he encontrado nada. Si alguien puede ayudarme a variar el
comportamiento, o bien explicarme por qué estoy equivocado al pensar
que primero se debe perder el foco de un control y luego ganarlo en
otro, le estaré muy agradecido. :-)

(*) Por cierto, que en JavaHispano.org necesitan desesperadamente
colaboración de los usuarios, casi como nos pasa a otros con nuestras
cosas de traducir navegadores (http://www.proyectonave.es/). Debe ser
algo ligado al carácter de los españoles...

Saludos.
--
If it's true that we are here to help others,
then what exactly are the OTHERS here for?
c***@cantv.net
2007-04-11 03:34:01 UTC
Permalink
Post by Ricardo Palomares Martinez
...
Esto funciona bien si salgo del campo pulsando [Tab] (lo que me lleva
a un JButton que hay debajo del campo de texto). Mi problema surge si,
mientras tengo el foco en el campo de texto, hago clic en otro nodo
del árbol. En este caso, TreeValueChanged se ejecuta *antes* de
LocusFost (lo cual no encuentro lógico; primero se pierde el foco del
campo de texto y sólo entonces puede cambiar el valor del nodo
seleccionado en el árbol, EMO).
Por más que busco, no he podido encontrar ningún documento que indique
la prioridad con la que se ejecutan los eventos. He buscado este mismo
problema en Internet, en los tutoriales de Java, en los archivos de
foros y listas de correo, y en la documentación de JavaHispano.org
(*), y no he encontrado nada. Si alguien puede ayudarme a variar el
comportamiento, o bien explicarme por qué estoy equivocado al pensar
que primero se debe perder el foco de un control y luego ganarlo en
otro, le estaré muy agradecido. :-)
Hola Ricardo,

En los viejos manuales de VB, te encontrabas con frecuencia
advertencias de que no podias asumir un orden particular en los
eventos. Luego llego VB6 con su "Validate", y nos simplifico un poco
la vida. Antes de Validate, tanto las validaciones como el proceso del
efecto de los cambios habia que hacerlos en LostFocus, y era una
pu*ada, ya que si a consecuencia de un fallo de validacion tenias que
traer el foco de regreso al control en proceso, disparabas el
LostFocus de quienquiera que lo hubiese recibido a consecuencia de la
accion que disparo el LostFocus original. Algo parecido es lo que te
ocurre (pero eso sin duda ya lo sabes).

Imagino que -a falta de algo parecido a validate (recorri buena parte
de la documentacion de Swing sin encontrar nada)= no nos quedara mas
remedio que trabajar con "contextos".

En tu caso, lo minimo seria un indicador (boolean isDirty;) que dice
que el JTextField de la derecha ha sido modificado (en el
DocumentListener: que perversos pueden ser los lenguajes). En el
LostFocus, si isDirty, procesas el cambio. Pero en el TreeValueChanged
verificas el estado de isDirty y actualizas lo que tengas que
actualizar antes de procesar efectivamente el evento. En ese proceso
de los cambios, restableces isDirty a false. Pero esto ya lo
sabias :-)

En la documentacion de Swing hay una seccion que describe el "AWT
Focus Subsystem" donde queda claro que primero se procesa la
activacion del componente que recibe el foco y luego la perdida del
foco del componente que lo entrega.

Aparentemente la torpeza en el manejo de los eventos tiene que ver con
las limitaciones que impone la independencia de plataforma (al menos
eso dicen ellos).

Habra que volver a las viejas cochinerias.


Salud!
Ricardo Palomares Martinez
2007-04-11 09:36:20 UTC
Permalink
Post by c***@cantv.net
Hola Ricardo,
No sé por qué, pero me imaginaba que ibas a tardar muy poco en
enseñarme a mí sobre Java... Lo que no creía es que fuera a ser TAN
poco tiempo. :-)
Post by c***@cantv.net
En tu caso, lo minimo seria un indicador (boolean isDirty;) que dice
que el JTextField de la derecha ha sido modificado (en el
DocumentListener: que perversos pueden ser los lenguajes). En el
LostFocus, si isDirty, procesas el cambio. Pero en el TreeValueChanged
verificas el estado de isDirty y actualizas lo que tengas que
actualizar antes de procesar efectivamente el evento. En ese proceso
de los cambios, restableces isDirty a false. Pero esto ya lo
sabias :-)
Tendré que hacerlo así, pero realmente creía que había un problema en
el orden de proceso de los eventos (y ahora estoy seguro de ello).
Post by c***@cantv.net
En la documentacion de Swing hay una seccion que describe el "AWT
Focus Subsystem" donde queda claro que primero se procesa la
activacion del componente que recibe el foco y luego la perdida del
foco del componente que lo entrega.
En realidad no, la documentación, imagino que te refieres a ésta:

http://java.sun.com/javase/6/docs/api/java/awt/doc-files/FocusSpec.html#FocusEventAndWindowEvent

es un pelín confusa y puede interpretarse como lo has hecho, pero lo
que quiere decir esa lista es que, en un control dado que pueda
recibir el foco, el que lo consiga supone que se ejecutará primero el
evento de activación de la ventana (si procede), el de ventana que
gana el foco (si procede), luego el del evento ganando el foco, y sólo
después de haber recibido el foco podrá perderlo, y si además el foco
va a otra ventana, perderá el foco la ventana y quedará desactivada.

Justo debajo de esa lista, en "Event Delivery", hay dos ejemplos, el
segundo de los cuales ilustra que primero pierde el foco el control
que lo tenía hasta ese momento (y con él, la ventana) y sólo después
lo ganan primero la nueva ventana y luego el nuevo control.

Así que aplicaré las viejas cochinerías que me sugieres (muchas
gracias) y preguntaré en la lista en inglés de NetBeans si esto debe
ser considerado un bug de Java.

Muchas gracias de nuevo.
--
If it's true that we are here to help others,
then what exactly are the OTHERS here for?
c***@cantv.net
2007-04-11 11:01:27 UTC
Permalink
Post by Ricardo Palomares Martinez
No sé por qué, pero me imaginaba que ibas a tardar muy poco en
enseñarme a mí sobre Java... Lo que no creía es que fuera a ser TAN
poco tiempo. :-)
Son solo tiros de salva... Aun tengo todo por aprender.
Post by Ricardo Palomares Martinez
Post by c***@cantv.net
En la documentacion de Swing hay una seccion que describe el "AWT
Focus Subsystem" donde queda claro que primero se procesa la
activacion del componente que recibe el foco y luego la perdida del
foco del componente que lo entrega.
En realidad no, la documentación, ... es un pelín confusa y puede
interpretarse como lo has hecho
Sobre todo cuando se la consulta apresuradamente despues de un dia
duro.

Habia interpretado la lista inmediatamente antes de Focus Delivery
(Focus Event and WindowsEvent) como una secuencia de eventos, y es
solo una lista.
Post by Ricardo Palomares Martinez
Así que aplicaré las viejas cochinerías que me sugieres (muchas
gracias) y preguntaré en la lista en inglés de NetBeans si esto debe
ser considerado un bug de Java.
Ahora me parece que si.

Y cuidado si a estas alturas, la ausencia de un evento Validate no
debiera ser considerada un bug.

Salud!
c***@cantv.net
2007-04-17 21:04:37 UTC
Permalink
Hola,

Hay algo parecido a Validate, el InputVerifier
[Component.setInputVerifier(InputVerifier inputVerifier)] que te
permite validar ANTES de la perdida del foco. La clase (no es una
interfaz) implementa tambien un metodo [shouldYieldFocus(JComponent
input)] que te permite decidir si el foco se entrega al componente que
lo reclama, o si se conserva dentro del componente activo.

Los JComponent tienen el metodo
setVerifyInputWhenFocusTarget(boolean), que te permite indicar si el
componente activo para el momento en que "este" reciba el foco deberan
ser validados. Sirve, por ejemplo, para no validar las operaciones al
pulsar el boton de cerrar un Frame (en terminos de VB6, es equivalente
a la propiedad CausesValidation de los controles).

Ambos funcionan "pobremente" cuando te mueves a diferentes niveles de
la jerarquia de contenedores (por ejemplo, tienes un JPanel dentro de
un JTabbedPane dentro de un JFrame, y pulsas un menu en el JFrame,
donde has indicado que no se active la validacion, pero la validacion
igual se activa).

Igual eso te sirve.

Salud!

Loading...