# JComboBox und setSelectedItem



## BlubBlub (27. Aug 2011)

Hi,
ich hab einem JComboBox Objekt einen ActionListener hinzugefügt.
In meine Programm, setze ich über setSelectedIndex() bzw. setSelectedItem()
den Wert der in der JComboBox angezeigt werden soll.
Nun wird aber jedes mal sobald ich die Methode setSelectedIndex() bzw. setSelectedItem()
verwende, der ActionListener aufgerufen. Gibt es eine Möglichkeit wie ich den Wert setzen kann
ohne dass der ActionListener aufgerufen wird? Nur wenn der Benutzer per Hand den Wert ändert
soll der ActionListener aufgerufen werden.


```
JComboBox cb = new JComboBox();
cb.addActionListener(new comboBoxActionListener());
cb.setSelectedIndex()   bzw.    cb.setSelectedItem();
```


----------



## bERt0r (27. Aug 2011)

Du kannst das Model der Combobox direkt bearbeiten, zugreifen darauf kannst du mit JComboBox.getModel()


----------



## eRaaaa (27. Aug 2011)

bERt0r hat gesagt.:


> Du kannst das Model der Combobox direkt bearbeiten, zugreifen darauf kannst du mit JComboBox.getModel()



???:L


----------



## beastofchaos (28. Aug 2011)

@eRaaa:
"JComboBox.setSelectedIndex(int index)" leitet auf setSelectedItem um. Da steht dann:


```
public void setSelectedItem(Object anObject) {
	Object oldSelection = selectedItemReminder;
        Object objectToSelect = anObject;
	if (oldSelection == null || !oldSelection.equals(anObject)) {
            // ...
	    // Ein paar Überprüfungen ...
            // ...
	    selectingItem = true;
	    dataModel.setSelectedItem(objectToSelect);             // Das ist die entscheidende Stelle, wo das Item geändert wird !!
	    selectingItem = false;

	    if (selectedItemReminder != dataModel.getSelectedItem()) {
		selectedItemChanged();
	    }
	}
	fireActionEvent();                          // Hier wird dann das ActionEvent aufgerufen !!
    }
```

Wenn du das "fireActionEvent()" umgehen willst, rufst du einfach (so wie dort) model.setSelectedItem(...) auf. Auf das Model komsmt du mit "get...". Also muss du einfach schreiben:


```
cb.getModel().getModel().setSelectedItem(comp);
```

Leider gibt es für das Model die Methode "setSelectedIndex()" nicht, weshalb du selber rausfinden musst, welche Komponente es ist.

Gruß, Thomas


----------



## Marco13 (28. Aug 2011)

Hast du asupropiert, ob der Event dann noch geworfen wird? Ich tippe nämlich auf JA. Wäre IMHO schlecht wenn nicht. 
Man wird sich wohl selbst merken müssen, ob man den Event verarbeiten will, oder nicht.


----------



## bERt0r (28. Aug 2011)

Marco hat recht, das Item event wird trotzdem geworfen weil das DefaultComboBox model selbst auch nochmal ein ListDataEvent event wirft. Das ganze ist anscheinend nur mit einem Workaround zu lösen:

```
public class ComboBoxTest extends JFrame {

	private JPanel contentPane;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					ComboBoxTest frame = new ComboBoxTest();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the frame.
	 */
	public ComboBoxTest() {
		
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 450, 300);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		setContentPane(contentPane);
		contentPane.setLayout(new BorderLayout(0, 0));
		
		JComboBox comboBox = new JComboBox(new String[] {"0","1", "2", "3", "4", "5"});
		class MyItemListener implements ItemListener {
			boolean enabled=true;
			public void itemStateChanged(ItemEvent e) 
			{
				if(enabled && e.getStateChange()==ItemEvent.SELECTED)
				{
					System.out.println(e.getItem());
				}
			}
			
			public void setEnabled(boolean b)
			{
				enabled=b;
			}
		};
		comboBox.addItemListener(new MyItemListener());
		comboBox.setSelectedIndex(4);
		for(ItemListener i:comboBox.getItemListeners())
		{
			if(i instanceof MyItemListener)
			{
				((MyItemListener) i).setEnabled(false);
			}
		}
		comboBox.setSelectedIndex(0);
		for(ItemListener i:comboBox.getItemListeners())
		{
			if(i instanceof MyItemListener)
			{
				((MyItemListener) i).setEnabled(true);
			}
		}
		
		comboBox.getModel().setSelectedItem("Ferdinand");
		comboBox.setSelectedItem("Karl-Heinz");
		

		contentPane.add(comboBox, BorderLayout.SOUTH);
	}

}
```


----------



## beastofchaos (28. Aug 2011)

Ja schon, aber es wird nun nur die Methode "contentsChanged(ListDataEvent e)" von allen ListDataListenern aufgerufen, nicht aber "actionPerformed(ActionEvent e)" von den ActionListenern.
Und genau das, wolltest du doch im ersten Post. 

Außerdem wird in deinem letzten Quellcode ein ItemListener hinzugefügt. Wird der dann auch aufgerufen? Schließlich werden nur die ListDataListener benutzt in "fireContentsChanged()".

Wenn du es noch mit einem ItemListener/ListDataListener machst und der wird aufgerufen, dann musst du das Problem halt mit einem boolean-Wert umgehen, der public z.B. in deinem ActionListener liegt...

Hier mal ein Beispiel, wie das bei einem ActionListener aussehen würde

```
public boolean dontPerforme = false;

...
dontPerforme = true;
cb.setSelectedIndex(2);
...

@Override
public void actionPerformed(ActionEvent e){
    if (dontPerforme){
        dontPerforme = false;
        return;
    }
    ...
}
```

Bitte klär mich jetzt nochmal auf, welchen Listener du überhaupt umgehen willst, bzw. welche Methode nicht aufgerufen werden soll(Action-, Item- oder ListDataListener).
Gruß, Thomas


----------



## BlubBlub (31. Aug 2011)

> Wenn du das "fireActionEvent()" umgehen willst, rufst du einfach (so wie dort) model.setSelectedItem(...) auf. Auf das Model komsmt du mit "get...". Also muss du einfach schreiben:
> 
> cb.getModel().getModel().setSelectedItem(comp);



Hi, also ich möchte sowohl den ActionListener als auch den ItemListener umgehen.
Bei mir feuert er aber weiterhin neben den ItemListenern auch den ActionListener,
wenn ich folgendes schreibe. 			


```
ComboBoxModel cbm = cb.getModel();
cbm.setSelectedItem("zwei");
```


----------



## Dit_ (31. Aug 2011)

beastofchaos hat gesagt.:


> Wenn du das "fireActionEvent()" umgehen willst, rufst du einfach (so wie dort) model.setSelectedItem(...) auf. Auf das Model komsmt du mit "get...". Also muss du einfach schreiben:
> 
> 
> ```
> ...



blöd das fireActionEvent() im Modell aufgerufen wird...  Stichwort: MVC

1. Möglichkeit. Initphase ohne Listener. Zuerst Items einfügen/selektieren, dann Listener registrieren.
2. Möglichkeit. Schlechte. Wenn du ein Item einfügst/selektierst, entferne alle Listener, nach dem Einfügen wieder Listener "adden".
3. Möglichkeit. Naja... Wenn du ein Item einfügst/selektierst, setze die globale variable vom Typ boolean auf true. 
	
	
	
	





```
ignoreAction = true
```
, danach wieder auf false.

```
@Override
            public void actionPerformed(ActionEvent e) {
                if (e.getSource().equals(_comboBox)) {
                    
                    if (ignoreAction) {
                        return;
                    } else {
                        ...
                    }
                }
                
            }
```


----------



## beastofchaos (31. Aug 2011)

@Dit_:
Kleiner Tipp, benutz lieber nicht "equals" bei der Abfrage. Du könntest zum Beispiel zwei gleiche Objekte haben, aber willst nur auf eines reagieren. An der Stelle vergleicht er ja mit " = " nicht, den Inhalt(der bei beiden gleich wäre), sondern die ID des jeweiligen Objekt. Und schließlich hat jedes Objekt eine eigene ID 


Und ich hab nochmal in JComboBox nachgeschaut. In "new JComboBox().setSelectedItem(new Object())" steht ganz am Ende:

```
fireActionEvent();
```

Im "new DefaultCOmboBoxModel().setSelectedItem(new Object())" steht nur: 

```
fireContentsChanged(this, -1, -1);
```

Und da steht:

```
protected void fireContentsChanged(Object source, int index0, int index1)
    {
	Object[] listeners = listenerList.getListenerList();
	ListDataEvent e = null;

	for (int i = listeners.length - 2; i >= 0; i -= 2) {
	    if (listeners[i] == ListDataListener.class) {
		if (e == null) {
		    e = new ListDataEvent(source, ListDataEvent.CONTENTS_CHANGED, index0, index1);
		}
		((ListDataListener)listeners[i+1]).contentsChanged(e);
	    }	       
	}
    }
```

Mir fältl aber grad auf, man kann einer JComboBox direkt keinen ListDataListener geben - nur dem Model. Möglicherweise werden damit alles ActionListener oder so aufgerufen (?). Sonst wüsst ich nicht, wie er auf die ActionListener und ItemListener (von denen ja bisher nirgendswo im Quelltext zu lesen war) zugreift. Sonst sind die 3 vorgeschlagenen Lösung eig ganz gut 

Gruß, Thomas


----------



## Dit_ (31. Aug 2011)

beastofchaos hat gesagt.:


> @Dit_:
> Kleiner Tipp, benutz lieber nicht "equals" bei der Abfrage. Du könntest zum Beispiel zwei gleiche Objekte haben, aber willst nur auf eines reagieren. An der Stelle vergleicht er ja mit " = " nicht, den Inhalt(der bei beiden gleich wäre), sondern die ID des jeweiligen Objekt. Und schließlich hat jedes Objekt eine eigene ID



Aha dann schau doch mal wie die Methode von JComboBox.equals(obj) implementiert ist. Und wozu bitteschön werde ich 2 gleiche ComboBoxen mit gleichem Inhalt haben? Ach ja es ist wohl kaum ID, sondern Referenz. ID hat ein Objekt in der DB.

kleiner Tipp


----------



## Dit_ (31. Aug 2011)

beastofchaos hat gesagt.:


> Mir fältl aber grad auf, man kann einer JComboBox direkt keinen ListDataListener geben - nur dem Model. Möglicherweise werden damit alles ActionListener oder so aufgerufen (?). Sonst wüsst ich nicht, wie er auf die ActionListener und ItemListener (von denen ja bisher nirgendswo im Quelltext zu lesen war) zugreift.



JComboBox implementiert selbst ActionListener
Wenn der Benutzer ein Objekt selectiert, passiert follgendes:

```
public void actionPerformed(ActionEvent e) {
        Object newItem = getEditor().getItem();
        setPopupVisible(false);
        getModel().setSelectedItem(newItem);
	String oldCommand = getActionCommand();
	setActionCommand("comboBoxEdited");
	fireActionEvent();
	setActionCommand(oldCommand);
    }
```


----------



## beastofchaos (31. Aug 2011)

Ist ja behindert  Und wie wird dieses implementierte "actionPerformed" von der JComboBox aufgerufen? Hab den Aufruf bisher noch nicht finden können :/

Und oh ja, hast recht, dass equals eigentlich das gleiche ist.


----------



## bERt0r (31. Aug 2011)

BlubBlub hat gesagt.:


> Hi, also ich möchte sowohl den ActionListener als auch den ItemListener umgehen.
> Bei mir feuert er aber weiterhin neben den ItemListenern auch den ActionListener,
> wenn ich folgendes schreibe.
> 
> ...



Hast du dir meinen Code schon angesehen/ihn ausprobiert? Ich vermute mal nein.
Ansonsten hoffe ich dass du Punkt 1 von dit (Initphase ohne Listener. Zuerst Items einfügen/selektieren, dann Listener registrieren.) berücksichtigst. Das ist eigentlich die normale Prozedur beim erstellen eines Komponenten.


----------



## BlubBlub (5. Sep 2011)

> 1. Möglichkeit. Initphase ohne Listener. Zuerst Items einfügen/selektieren, dann Listener registrieren.
> 2. Möglichkeit. Schlechte. Wenn du ein Item einfügst/selektierst, entferne alle Listener, nach dem Einfügen wieder Listener "adden".
> 3. Möglichkeit. Naja... Wenn du ein Item einfügst/selektierst, setze die globale variable vom Typ boolean auf true. ignoreAction = true , danach wieder auf false.



Hi, 
also die erste Möglichkeit kommt nur beim einmaligen Intialisieren in Betracht. In meinem Programm wird aber dynamisch je nach Benutzerauswahl neu initialisiert. Kurz gesagt die erste Möglichkeit reicht nicht.
Die zweite Möglichkeit habe ich auch schon selbst in Betracht gezogen und auch momentan implementiert, weil dies momentan die einzig zuverlässige Lösung ist, meines achtens.
Die dritte Möglichkeit ist etwas aufwändiger in der Umsetzung, auf Grund der Variablen. Durch Erstellung eines vernünftigen Konzeptes könnte man diese sicherlich in erwägung ziehen, aber um mein Programm nicht unnötig zu verkomplizieren und bereits implementiere Konzepte und Zusammenhänge nicht neu aufbrechen zu müssen, habe ich mich für Möglichkeit 2 entschieden, auch wenn sie nicht so schön ist.


----------

