Swing: ¿Hay una manera de diferenciar entre un evento de evento causado por el usuario y uno causado por la aplicación?

StackOverflow https://stackoverflow.com/questions/176150

Pregunta

Estoy trabajando con un cuadro combinado en una aplicación basada en Swing, y me resulta difícil descubrir qué hacer para diferenciar un ItemEvent que se genera a partir de un evento de usuario frente a uno causado por la aplicación.

Por ejemplo, Digamos que tengo un cuadro combinado, ' combo ' y estoy escuchando los eventos itemStateChanged con mi ItemListener, ' listener '. Cuando un usuario cambia la selección al elemento 2 o ejecuto la línea (pseudocódigo):

combo.setSelection(2)

.. parece que no soy capaz de diferenciar estos eventos.

Dicho esto, no soy un experto en Swing de ninguna manera, así que pensé que iba a preguntar.

¡Gracias!

¿Fue útil?

Solución

La ley de Acción y Reacción es bastante clara :). Si intenta reaccionar ante un cambio, no es necesario distinguir entre usuario y aplicación. Solo puedo imaginar un caso de uso en el que necesite " distinguir " ;. El caso donde la aplicación está mostrando algunos datos. En este caso, probablemente tenga un modelo de datos para su aplicación. Y también hay un detector de cambios en este modelo y la GUI de la aplicación reaccionará estableciendo valores en los componentes. Y también. Si el usuario selecciona algo en el componente GUI. El modelo de datos reaccionará cambiando el valor. En este caso, es fácil configurar algún tipo de estado de solo lectura en el modelo de datos que notificará al modelo que ignore CUALQUIER evento proveniente de objetos observados. Este conjunto de notificaciones debe ejecutarse en EDT y no hay ningún problema con el marcado. Pequeño ejemplo:

class ApplicationDataModel {

    private Flag current = Flag.RW;

    public void setData(ApplicationData data) {
        current = Flag.RO;
        setDataImpl(data);
        notifyObservers();
        current = Flag.RW;
    }

    public void reaction(Event e) {
        if (flag = Flag.RO) return;
        ...
    }

}

Tenga cuidado con las marcas y no se olvide de los hilos. Si está llamando a setData desde otro hilo, entonces EDT tendrá problemas. Por supuesto. La extracción del objeto ApplicationData debe ejecutarse en un subproceso diferente;). En general, repiense el diseño de su aplicación.

Otros consejos

Si el usuario selecciona el elemento 2 o la API llama a setSelection (2), el evento aparecerá igual .

La solución a su problema podría ser volver a pensar qué desea que haga el código itemStateChanged cuando cambie la selección. ¿Por qué su aplicación funcionaría de manera diferente bajo cada condición? Tal vez hay similitudes que puedes usar para tu ventaja.

Ten cuidado cuando uses banderas . El evento itemStateChanged se producirá en el subproceso de distribución de eventos, que es un subproceso diferente al que estableció el estado de la bandera. Esto significa que el uso de una bandera puede no ser 100% confiable.

Puede establecer una bandera en su código antes de configurar la selección, y luego verificar esta bandera en el oyente (y deshabilitar la bandera si está establecida) ...

Puede haber una mejor manera desde Java 6, pero esta es la forma en que siempre solía hacerlo ...

[Editar] : como lo señala David, deberá establecer la bandera (y actualizar el combo) en la EDT usando SwingUtilities.invokeLater o similar (debe hacer esto de todos modos, mientras están cambiando un control de UI)

Si necesita diferenciar los eventos, probablemente haya algo en su diseño que necesite un replanteamiento. El objetivo principal de MVC es desacoplar los cambios al modelo de los clics reales del usuario con el mouse.

Quizás debería volver a plantear la pregunta en términos de por qué que alguna vez quiera diferenciar entre estas dos situaciones. Entonces podríamos proporcionar alguna orientación sobre una forma diferente de lograr el objetivo.

Entonces supongo que desea que la selección del usuario realice alguna acción en lugar de un simple cambio de estado directo. Este es un problema causado por la flexibilidad limitada (la flexibilidad siempre será limitada, especialmente si tiene flexibilidad en otras direcciones).

Mi sugerencia:

En primer lugar, siempre vaya directamente al uso del modelo en Swing. Los widgets son complicados y quieres que se dividan las diferentes preocupaciones. Afortunadamente, Swing ya está allí con sus modelos.

Un patrón común es tener delegación entre modelos. Así que en este caso tienes el " real " Modelo por defecto que guarda tus datos. Inserte entre JComboBox y ComboBoxModel real y delegue ComboBoxModel que realiza acciones en las instrucciones de cambio de estado. El código de su aplicación debe ignorar el JComboBox e ir directamente al ComboBoxModel real sin pasar por el modelo de delegación. Así que en un diagrama:

User -- JComboBox -- ActionComboBoxModel -- DefaultComboBoxModel -- Application code
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top