# JCombobox mit <neuer Eintrag>



## Dagobert (24. Aug 2010)

Guten morgen,
ich habe mal wieder ein neues Problem in sachen GUI programmierung.
Ich habe z.B. ein Comboboxmodel welches eine Liste von Orten anzeigt. Jetzt möchte ich aber immer das das Letzte/Erste Element der Combobox immer ein "Neues Element" Eintrag ist und auch ein neues Element anlegt.
Wie bekomme ich so etwas hin?

mfg. Dagobert


----------



## eRaaaa (24. Aug 2010)

Hmm..ohne jetzt ein großes Hexenwerk daraus zu machen, würde das evtl. schon mit einem normalen DefaultComboBoxModel und einem ItemListener gehen?!
Im Listener dann evtl. so etwas wie

```
public void itemStateChanged(ItemEvent e) {
				if (e.getStateChange() == ItemEvent.SELECTED) {
					if (e.getItem().equals("Neuer Eintrag")) {
						//hole neues objekt und fuege hinzu (hier mit foo angedeutet)
						model.insertElementAt("Foo", model.getSize() - 1);
						model.setSelectedItem("Foo");
					}
				}
			}
```
Vorrausgesetzt du hast zuvor dem Model als letztes Element "Neuer Eintrag" hinzugefügt...die neuen Einträge werden dann immer VOR diesem eingetragen...

Ansonsten evtl. etwas Code zeigen oder nochmal etwas genauer erklären


----------



## Dagobert (25. Aug 2010)

Okay ich habe aber leider kein DefaultComboBoxModel sonder benutze eine vorhandene Datenstruktur die Orte verwaltet. 
Aber ich kann doch auch keinen "Neue Ort" nur für die GUI in der Datenstruktur anlegen???! (Oder macht man das so?) Ich glaube es sollte sogar gehen, aber es wirkt unschön oder?:
Ich lege einen "Neuen Ort" in die Datenstuktur, wenn ich in der JCombobox den "Neuen Ort" auswähle ändert sich der Button daneben von  löschen in neu. Dann öffnet sich ein Dialog, welches den "Neuen Ort" bearbeitet und ihn einen richtigen Namen gibt?!
Ich probier es mal melde mich später nocheinmal.

mfg. Dagobert


----------



## Dagobert (25. Aug 2010)

Ich hab nochmal ne frage zur Combobox
Wenn ich im Model neue Elemente anlege wird meine Combobox aber nicht aktualisiert. Von nem TableModel weiß ich das ich Events feuern muss, aber wie mache ich das bei nem Comboboxmodel?

mfg. Dagobert


----------



## eRaaaa (25. Aug 2010)

Dagobert hat gesagt.:


> Okay ich habe aber leider kein DefaultComboBoxModel sonder benutze eine vorhandene Datenstruktur die Orte verwaltet.



Mhm? Was heißt das? Kannst du das etwas näher erklären? Meinst du, du hast einen Vector in denen du die Orte verwaltest und hast dann new ComboBox(vector) geschrieben?
Die Combobox benutzt immer intern ein DefaultComboBoxModel(ausser du übergibst eben ein eigenes), d.h. du könntest dir dieses über getModel() holen(casten evtl.)



Dagobert hat gesagt.:


> Ich hab nochmal ne frage zur Combobox
> Wenn ich im Model neue Elemente anlege wird meine Combobox aber nicht aktualisiert. Von nem TableModel weiß ich das ich Events feuern muss, aber wie mache ich das bei nem Comboboxmodel?


Kommt eben auf das Model drauf an, beim DefaultComboBoxModel musst du dich um gar nichts kümmern. Hast du dein eigenenes Model welches z.B. AbtractListModel erweitert, musst du auch hier jeweils eine der fire-Methoden aufrufen (fireIntervalAdded, fireIntervalRemoved,fireContentsChanged - je nachdem)


----------



## Marco13 (25. Aug 2010)

Wenn das Modell richtig implementiert ist, sollten auch die Events geworfen werden. 

Wichtig wäre zu wissen, wie das Modell im Moment aussieht. Ich könnte mir vorstellen, dass ein Delegate für diese Aufgabe ganz gut geeignet wäre: Man hat ein Modell, in dem die "Echten" Daten liegen. Ein anderes Modell _enthält_ das echte Modell, und gibt zusätzlich immer EIN Element mehr zurück (nämlich "Neuer Eintrag"). 

Hab's mal grob angetestet

```
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.ListDataListener;

class NewEntryComboBoxModel implements MutableComboBoxModel
{
    public static String NEW_ENTRY_ELEMENT = "New entry...";
    
    private MutableComboBoxModel delegate;
    private boolean newEntryElementSelected = false;

    public NewEntryComboBoxModel(MutableComboBoxModel delegate)
    {
        this.delegate = delegate;
    }
    
    public void addListDataListener(ListDataListener l)
    {
        delegate.addListDataListener(l);
    }

    public Object getElementAt(int index)
    {
        if (index == delegate.getSize())
        {
            return NEW_ENTRY_ELEMENT;
        }
        return delegate.getElementAt(index);
    }

    public void setSelectedItem(Object anItem)
    {
        if (NEW_ENTRY_ELEMENT.equals(anItem))
        {
            newEntryElementSelected = true;
        }
        else
        {
            newEntryElementSelected = false;
            delegate.setSelectedItem(anItem);
        }
    }

    public Object getSelectedItem()
    {
        if (newEntryElementSelected)
        {
            return NEW_ENTRY_ELEMENT;
        }
        return delegate.getSelectedItem();
    }

    public int getSize()
    {
        return delegate.getSize()+1;
    }

    public void removeListDataListener(ListDataListener l)
    {
        delegate.removeListDataListener(l);
    }

    @Override
    public void addElement(Object obj)
    {
        delegate.addElement(obj);
    }

    @Override
    public void insertElementAt(Object obj, int index)
    {
        delegate.insertElementAt(obj, index);
    }

    @Override
    public void removeElement(Object obj)
    {
        delegate.removeElement(obj);
    }

    @Override
    public void removeElementAt(int index)
    {
        delegate.removeElementAt(index);
    }

    
}


public class ComboBoxModelWithAddTest extends JPanel implements ActionListener
{
    public static void main(String[] args)
    {
        javax.swing.SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowGUI();
            }
        });
    }
    
    private MutableComboBoxModel model = new NewEntryComboBoxModel(new DefaultComboBoxModel());
    
    public ComboBoxModelWithAddTest()
    {
        super(new BorderLayout());

        String[] items = { "First", "Second", "Third" };
        for (String item : items)
        {
            model.addElement(item);
        }
        JComboBox cb = new JComboBox(model);
        cb.setSelectedIndex(0);
        cb.addActionListener(this);
        add(cb, BorderLayout.PAGE_START);
        setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
    }

    public void actionPerformed(ActionEvent e)
    {
        JComboBox cb = (JComboBox) e.getSource();
        String item = (String) cb.getSelectedItem();
        System.out.println("Selected: " + item);
        if (item.equals(NewEntryComboBoxModel.NEW_ENTRY_ELEMENT))
        {
            System.out.println("Adding new entry");
            String s = "Element "+String.valueOf(System.currentTimeMillis());
            model.addElement(s);
            model.setSelectedItem(s);
        }
    }

    private static void createAndShowGUI()
    {
        JFrame frame = new JFrame("ComboBoxDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JComponent newContentPane = new ComboBoxModelWithAddTest();
        newContentPane.setOpaque(true);
        frame.setContentPane(newContentPane);
        frame.setSize(300,200);
        frame.setVisible(true);
    }

}
```


----------



## Dagobert (25. Aug 2010)

Okay meine Klasse die das Model beinhaltet sieht etwas anders aus  Das fängt schon damit an das ich ComboBoxModel implementiere oO

Hier ist mal mein Code:

```
package model;

import java.util.ArrayList;

import javax.swing.ComboBoxModel;
import javax.swing.event.ListDataListener;

/**
 * 
 * H&auml;t Veranstaltungen.
 */
public class Spielplan implements ComboBoxModel{

	/**
	 * @clientCardinality 1
	 * @clientNavigability NAVIGABLE
	 * @supplierCardinality *
	 */

	/**
	 * Attribut f&uuml;r den Namen des Spielplans.
	 */
	private String spname;

	/**
	 * Attribut f&uuml;r die aktuelle Veranstaltung.
	 */
	private Veranstaltung currVeranstaltung;

	/**
	 * Attribut f&uuml;r die Liste der Veranstaltungen.
	 */
	private ArrayList<Veranstaltung> veranstaltungen;

	/**
	 * Konstruktor: Legt einen neuen Spielplan an, indem eine neue ArrayListe
	 * der Veranstaltungen angelegt wird und der Name des Spielplans auf den
	 * &uuml;bergebenen Namen gesetzt wird.
	 * 
	 * @param name
	 *            Name des Spielplans
	 *   @return Leerer Spielplan mit gesetztem Namen. 
	 */
	public Spielplan(String name) {
		super();
		veranstaltungen = new ArrayList<Veranstaltung>();
		this.spname = name;
	}

	/**
	 * Gibt die Anzahl der Veranstaltungen zur&uuml;ck.
	 * @return Anzahl der Veranstaltungen im Spielplan.
	 */
	public int getAnzahlVeranstaltungen() {
		return veranstaltungen.size();
	}

	/**
	 * Gibt die i-te Veranstaltung zur&uuml;ck
	 * 
	 * @param i
	 *            Position der gew&uuml;nschten Veranstaltung in der Liste.
	 * @exception VeranstaltungNichtVorhandenException
	 *                Diese Exception wird dann geworfen, wenn der Index der
	 *                gesuchten Verantaltung gr&ouml;&szlig;er als die L&auml;nge der Liste ist.
	 * @return Veranstaltung mit Position Index i.
	 */
	public Veranstaltung getVeranstaltung(int i)
			throws VeranstaltungNichtVorhandenException {
		if (i >= getAnzahlVeranstaltungen()) {
			throw new VeranstaltungNichtVorhandenException();
		} else {
			return veranstaltungen.get(i);
		}
	}

	/**
	 * F&uuml;gt eine Veranstaltung zum Spielplan hinzu.
	 * 
	 * @param nveranstaltung
	 *            Veranstaltung, die hinzugef&uuml;gt werden soll.
	 */
	public void addVeranstaltungen(Veranstaltung nveranstaltung) {
		veranstaltungen.add(nveranstaltung);
	}

	/**
	 * L&ouml;scht eine Veranstaltung aus dem Spielplan.
	 * 
	 * @param nveranstaltung
	 *            Veranstaltung, die gel&ouml;scht werden soll.
	 * @exception VeranstaltungNichtVorhandenException
	 *                Diese Exception wird dann geworfen, wenn die
	 *                Veranstaltung, die gel&ouml;scht werden soll, nicht in der
	 *                Liste vorhanden ist.
	 */
	public void removeVeranstaltung(Veranstaltung nveranstaltung)
			throws VeranstaltungNichtVorhandenException {
		for (int i = 0; i < veranstaltungen.size(); i++) {
			if (veranstaltungen.get(i).equals(nveranstaltung)) {
				veranstaltungen.remove(i);
			}
		}
		throw new VeranstaltungNichtVorhandenException();
	}

	/**
	 * Gibt den Namen des Spielplanes zur&uuml;ck.
	 * @return Der Name des Spielplanes.
	 */
	public String getName() {
		return spname;
	}

	/**
	 * Gibt die aktuelle ausgesuchte Veranstaltung zur&uuml;ck.
	 * @return Die ausgew&auml;hlte Veranstaltung.
	 */
	public Object getSelectedItem() {
		return currVeranstaltung;
	}

	/**
	 * Setzt die aktuelle Veranstaltung auf das &uuml;bergebene Objekt.
	 * 
	 * @param anItem
	 *            &Uuml;bergebene Objekt (erwartet wird eine Veranstaltung)
	 */
	public void setSelectedItem(Object anItem) {
		for (Veranstaltung v : veranstaltungen) {
			if (v.getName().equals(anItem)) {
				currVeranstaltung = v;
				return;
			}
		}
	}

	public void addListDataListener(ListDataListener l) {
		// TODO Auto-generated method stub
	}

	/**
	 * Gibt die i-te Veranstaltung aus der Liste zur&uuml;ck.
	 * 
	 * @param index
	 *            Index/Nummer der gesuchten Veranstaltung.
	 */
	public Object getElementAt(int index) {
		return veranstaltungen.get(index).getName();
	}

	/**
	 * Gibt die Anzahl der Veranstaltungen im Spielplan zur&uuml;ck.
	 * @return Die Anzahl der Veranstaltungen im Spielplan.
	 */
	public int getSize() {
		return veranstaltungen.size();
	}

	public void removeListDataListener(ListDataListener l) {
		// TODO Auto-generated method stub
	}

	/**
	 * Gibt die aktuelle Veranstaltung zur&uuml;ck.
	 * 
	 * @return Aktuelle Veranstaltung.
	 */
	public Veranstaltung getCurrVeranstaltung() {
		return this.currVeranstaltung;
	}
	
	public String toString(){
		return this.spname;
	}
}
```

mfg. Dagobert


----------



## Marco13 (25. Aug 2010)

Wenn ich das richtig sehe dient das nur dem Zweck, ein "Typsicheres" ComboBoxModel zu haben (d.h. eins wo man direkt mit Veranstaltungen rumhantieren kann, und nicht mehr Objects casten muss). Es ist auch "fast" ein _Mutable_ComboBoxModel, nur dass eben "addVeranstaltung" existiert anstatt "addElement". Aber spätestens außerhalb wirst du sowieso was machen müssen, weil der Eintrag "<neuer Eintrag>" eben NICHT vom Typ "Veranstaltung" ist.


----------



## Dagobert (25. Aug 2010)

Ich bin echt am verzweifeln oO
Wie bekomme ich meine JCombobox dazu hinzugefügte Elemente auch anzuzeigen, und nicht nur ein graues Kästchen? oO Ich krieg es einfach nicht hin, auch nicht mit nen MutableComboboxModel oO
Bitte nochmals um hilfe. =(
jetzt habe ich es mit JComboBox.addItem() versucht, aber auch da wird nichts angezeigt, ich weis nicht ob es da daran liegt das ich nen eigenes Model verwende.

mfg. Dagobert


----------



## Marco13 (25. Aug 2010)

Es ist schwer zu sagen, woran es hakt. Und insbesondere tauchen viele Fragezeichen auf, weil man den geposteten Code und die Fragen nicht in einen größeren Zusammenhang einordnen kann (da sieht einiges seltsam aus).
Wenn du jetzt das MutableComboBoxModel implementiert hast, hast du vermutlich die Listener nicht richtig benachrichtigt. Hast du schon mal überlegt, vom DefaultComboBoxModel zu erben...? Das könnte einiges einfacher machen....


----------



## Dagobert (26. Aug 2010)

So ich habe jetzt das ganze von DefaultComboboxModel erben lassen, jetzt wird auch alles richtig gezeichnet. Was oben falsch ist weiß ich immer noch nicht, aber immerhin gehts jetzt und das ist erstmal die Hauptsache im augenblick.
Vielen dank für eure Mühen

mfg. Dagobert


----------

