Swing: esiste un modo per distinguere tra un ItemEvent causato dall'utente e uno causato dall'applicazione?

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

Domanda

Sto lavorando con una casella combinata in un'applicazione basata su Swing e non riesco a capire cosa fare per differenziare un ItemEvent generato da un evento utente rispetto a uno causato dall'applicazione.

Ad esempio, diciamo che ho una casella combinata, ' combo ' e sto ascoltando gli eventi itemStateChanged con il mio ItemListener, ' listener '. Quando un utente modifica la selezione sull'elemento 2 o eseguo la riga (pseudocodice):

combo.setSelection (2)

.. sembra che non sia in grado di distinguere questi eventi.

Detto questo, non sono assolutamente un esperto di Swing, quindi ho pensato di chiedere.

Grazie!

È stato utile?

Soluzione

La legge di azione e reazione è abbastanza chiara :). Se si tenta di reagire al cambiamento, non è necessario distinguere tra utente e applicazione. Posso immaginare un solo caso d'uso in cui è necessario "distinguere". Il caso in cui l'applicazione visualizza alcuni dati. In questo caso hai, probabilmente, un modello di dati per la tua applicazione. Inoltre, in questo modello sono presenti alcuni listener di modifiche e la GUI dell'applicazione reagirà impostando i valori sui componenti. E anche. Se l'utente seleziona qualcosa nel componente GUI. Il modello di dati reagirà modificando il valore. In questo caso è facile impostare una sorta di stato di sola lettura sul modello di dati che notificherà al modello di ignorare QUALSIASI evento proveniente da oggetti osservati. Questo set di notifiche dovrebbe essere eseguito in EDT e non ci sono problemi con la segnalazione. Piccolo esempio:

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;
        ...
    }

}

Fai attenzione alle segnalazioni e non dimenticare di eseguire il threading. Se stai chiamando setData da un altro thread, allora EDT stai andando nei guai. Ovviamente. L'estrazione dell'oggetto ApplicationData deve essere eseguita in thread diversi;). In generale, ripensare il design dell'applicazione.

Altri suggerimenti

Se l'utente seleziona l'articolo 2 o l'API chiama setSelection (2), l'evento apparirà lo stesso .

La soluzione al tuo problema potrebbe essere nel ripensare a ciò che vuoi che faccia il codice itemStateChanged quando cambia la selezione. Perché la tua app dovrebbe funzionare diversamente in ogni condizione? Forse ci sono somiglianze che puoi usare a tuo vantaggio.

Fai attenzione quando usi le bandiere . L'evento itemStateChanged si verificherà sul thread di invio eventi, che è un thread diverso da quello su cui si imposta lo stato del flag. Ciò significherebbe che l'uso di una bandiera potrebbe non essere affidabile al 100%.

Puoi impostare un flag nel tuo codice prima di impostare la selezione, quindi controllare questo flag nel listener (e annullare il flag se è impostato) ...

Potrebbe esserci un modo migliore rispetto a Java 6, ma questo è il modo in cui l'ho sempre usato ...

[Modifica] : come sottolinea David, dovrai impostare la bandiera (e aggiornare la combo) nell'EDT usando SwingUtilities.invokeLater o simile (dovresti farlo comunque, come stanno cambiando un controllo dell'interfaccia utente)

Se devi distinguere gli eventi, probabilmente c'è qualcosa nel tuo design che ha bisogno di un ripensamento. Il punto centrale di MVC è disaccoppiare le modifiche al modello dagli effettivi clic del mouse dell'utente.

Forse dovresti riformulare la domanda in termini di perché vorresti mai distinguere tra queste due situazioni. Potremmo quindi fornire alcune indicazioni su un modo diverso di raggiungere l'obiettivo.

Quindi suppongo che desideri che la selezione dell'utente esegua qualche azione piuttosto che un semplice cambio di stato diretto. Questo è un problema causato da una flessibilità limitata (la flessibilità sarà sempre limitata, in particolare se si dispone di flessibilità in altre direzioni).

Il mio suggerimento:

In primo luogo, vai sempre dritto all'utilizzo del modello in Swing. I widget sono complicati e si desidera dividere le diverse preoccupazioni. Fortunatamente Swing è già lì con i suoi modelli.

Un modello comune è avere una delega tra i modelli. Quindi in questo caso hai il "reale" modello predefinito che contiene i tuoi dati. Inserire tra JComboBox e ComboBoxModel reale e delegare ComboBoxModel che esegue azioni sulle istruzioni di modifica dello stato. Il codice dell'applicazione dovrebbe ignorare JComboBox e andare dritto per il vero ComboBoxModel bypassando il modello di delega. Quindi in un diagramma:

User -- JComboBox -- ActionComboBoxModel -- DefaultComboBoxModel -- Application code
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top