Swing: Existe uma maneira de diferenciar entre um ItemEvent causado pelo usuário e outra causada pelo aplicativo?

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

Pergunta

Eu estou trabalhando com um combobox em um aplicativo baseado em Swing, e eu estou tendo um momento difícil descobrir o que fazer para diferenciar entre um ItemEvent que é gerado a partir de um evento do usuário contra um causado pela aplicação.

Por exemplo, digamos que eu tenho um combobox, 'combo' e eu estou ouvindo eventos itemStateChanged com minha ItemListener, 'listener'. Quando qualquer um usuário altera a seleção do item 2 ou eu executar a linha (pseudocódigo):

combo.setSelection(2)

.. parece que eu não sou capaz de dizer estes eventos separados.

Dito isto, eu não sou nenhum perito do balanço, por qualquer meio, então eu pensei que eu ia perguntar.

Obrigado!

Foi útil?

Solução

A Ação e Reação lei é bastante clara :). Se você tentar reagir a mudança, não há necessidade de distinguir entre o usuário ea aplicação. Eu posso imaginar apenas um caso de uso onde você precisa "distinguir". O caso em que aplicativo está exibindo alguns dados. Neste caso você tem, provavelmente, o modelo de dados para a sua aplicação. E também há alguns ouvinte de alteração neste modelo e aplicação GUI vai reagir definindo valores para os componentes. E também. Se o usuário seleciona qualquer coisa em componente GUI. O modelo de dados vai reagir alterando o valor. Neste caso, é fácil de configurar algum tipo de estado somente leitura no modelo de dados que irá notificar modelo para ignorar qualquer evento proveniente de objetos observados. Este conjunto de notificação deve ser executado em EDT e não há nenhum problema com a sinalização. Pequeno exemplo:

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

}

Tenha cuidado com a sinalização e não se esqueça sobre threading. Se você está chamando setData de outro segmento, em seguida, EDT você vai ter problemas. Claro. A extracção do objecto ApplicationData tem de ser executado em fio diferente;). Na concepção geral, repensar a sua aplicação.

Outras dicas

Se item o usuário seleciona 2 ou o setSelection chamadas de API (2), o evento será exibido o mesmo .

A solução para o seu problema pode estar em re-pensar o que você deseja que o código itemStateChanged que fazer quando a seleção é alterada. Por que o seu trabalho aplicativo diferente em cada condição? Talvez existam semelhanças que você pode usar a sua vantagem.

Tenha cuidado ao usar bandeiras . O evento itemStateChanged ocorrerá no segmento de despacho de evento, que é um segmento diferente do que aquele em que você definir o estado da bandeira. Isto significaria que o uso de uma bandeira pode não ser 100% confiável.

Você pode definir um sinalizador no seu código antes de definir a seleção e, em seguida, verificar se há esta bandeira no ouvinte (e resetar o flag se estiver definido) ...

Pode haver uma maneira melhor desde Java 6, mas esta é a maneira que eu sempre costumava fazer isso ...

[Edit] : Como David aponta, você precisará definir o sinalizador (e atualizar o combo) no EDT usando SwingUtilities.invokeLater ou similar (você deve fazer isso de qualquer maneira, como você estão mudando um controle UI)

Se você precisa dizer os eventos de distância, em seguida, provavelmente há algo sobre seu projeto que precisa de um repensar. O ponto inteiro de MVC é a mudanças dissociar ao modelo a partir dos cliques reais do mouse do usuário.

Talvez você deve repetir a pergunta em termos de por que você jamais iria querer diferenciar entre estas duas situações. Poderíamos, então, fornecer alguma orientação sobre uma maneira diferente de alcançar a meta.

Então, eu estou supondo que você quer que a seleção do usuário para executar alguma ação em vez de apenas uma mudança de estado direta velho liso. Este é um problema causado pela pouca flexibilidade (flexibilidade é sempre vai ser limitado, especialmente se você tiver flexibilidade em outras direções).

A minha sugestão:

Em primeiro lugar, sempre ir direto para usando o modelo em Swing. Os widgets são a forma complicada e você quer preocupações diferentes para ser dividido. Felizmente balanço já está lá com seus modelos.

Um padrão comum é ter de delegação entre modelos. Portanto, neste caso você tem o modelo padrão "real" que mantém seus dados. Insira entre o JComboBox e ComboBoxModel real e delegando ComboBoxModel que realiza ações em instruções de mudança de estado. O código do aplicativo deve ignorar o JComboBox e ir direto para o ComboBoxModel verdadeira ignorando o modelo de delegação. Assim, em um diagrama:

User -- JComboBox -- ActionComboBoxModel -- DefaultComboBoxModel -- Application code
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top