JComboBox / PopupMenuListener Problem

Tsunamii

Mitglied
Hallo,

ich hoffe diese Problem lässt sich so schnell wie möglich lösen.
Und zwar will ich den Inhalt einer ComboBox immer dann ändern wenn das PopupMenu sichtbar wird bzw wenn dies wieder verschwindet. Benötigt wird das ganze für Länderkennzeichen, d.h. wenn das PopupMenu verschwindet soll z.B. D oder JA zu sehen sein aber wenn das PopupMenu sichtbar ist soll man dann Deutschland bzw Jamaika sehen können.

Hier mal ein Auszug aus meinem Programm:

Code:
addPopupMenuListener(new MyComboBoxListener());

// ...

public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
	JComboBox box = (JComboBox) e.getSource();
	if (box.getName().equals("LKZ")) {
		int selected = box.getSelectedIndex();
		ComboBoxModel model = new DefaultComboBoxModel(getAllShortLKZ());
		box.setModel(model);
		box.setSelectedIndex(selected);
	}
}

public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
	JComboBox box = (JComboBox) e.getSource();
	if (box.getName().equals("LKZ")) {
		int selected = box.getSelectedIndex();
		ComboBoxModel model = new DefaultComboBoxModel(getAllLongLKZ());
		box.setModel(model);
		box.setSelectedIndex(selected);
	}
}

Es funktioniert soweit alles wie geplant, d.h. die Werte werden ausgetauscht,
nur wenn ich das Popup öffne verschwindet es sofort wieder und man kann somit auch keine neue Auswahl treffen.
Auch bleibt die Breite des PopupMenus wie vorher, d.h. die Länder sind nicht wirklich lesbar.

Über schnelle Hilfe würde ich mich sehr freuen.
 
Hab das Problem mittlerweile selbst gelöst bekommen :)
Zu den Fehlern:

- Sofortiges Verschwinden der ComboBox
Hierbei hat es sich um ein Problem des LayoutManagers gehandelt, habe die Breite der ComboBox nun festgesetzt was dazu führt, dass das PopupMenu auch sichtbar bleibt.

- Breite des PopupMenus passt sich nicht an die Werte an
Hierzu habe ich die ComboBox um eine eigene UI und einen PopupListener erweitert, die zum einen die Werte ändern aber beim sichtbar machen des PopupMenus, die Breite neu bestimmen.

Hier mal der Quellcode meiner neuen ComboBox:
Code:
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Rectangle;
import java.util.Vector;

import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.plaf.basic.BasicComboPopup;
import javax.swing.plaf.basic.ComboPopup;

import sun.font.FontDesignMetrics;

import com.sun.java.swing.plaf.windows.WindowsComboBoxUI;

public class ChangeableSteppedComboBox extends JComboBox {

	String[] visible = { "Deutschland", "Spanien", "Griechenland", "Jamaika" };
	String[] invisible = { "D", "E", "GR", "JA" };

	private static final long serialVersionUID = 1L;
	protected int popupWidth;

	public ChangeableSteppedComboBox() {
		super();
		setUI(new MyComboBoxUI());
		addPopupMenuListener(new MyPopupMenuListener());
		popupWidth = 0;
	}

	public ChangeableSteppedComboBox(ComboBoxModel pModel) {
		super(pModel);
		setUI(new MyComboBoxUI());
		addPopupMenuListener(new MyPopupMenuListener());
		popupWidth = 0;
	}

	public ChangeableSteppedComboBox(final Object[] pItems) {
		super(pItems);
		setUI(new MyComboBoxUI());
		addPopupMenuListener(new MyPopupMenuListener());
		popupWidth = 0;
	}

	public ChangeableSteppedComboBox(Vector<Object> pItems) {
		super(pItems);
		setUI(new MyComboBoxUI());
		addPopupMenuListener(new MyPopupMenuListener());
		popupWidth = 0;
	}

	public void setPopupWidth(int width) {
		popupWidth = width;
	}

	public Dimension getPopupSize() {
		Dimension size = getSize();
		if (popupWidth < 1)
			popupWidth = size.width;
		return new Dimension(popupWidth, size.height);
	}

	public int getPopupWidth() {
		int newWidth = 0;
		Font font = new Font("Arial", Font.PLAIN, 10);
		FontDesignMetrics metrics = FontDesignMetrics.getMetrics(font);
		int temp;
		DefaultComboBoxModel model = (DefaultComboBoxModel) this.getModel();
		for (int i = model.getSize() - 1; i >= 0; i--) {
			newWidth = ((temp = metrics.stringWidth((String) model
					.getElementAt(i))) > newWidth) ? temp : newWidth;
		}
		System.out.println(newWidth);
		return newWidth;
	}

	public void changeItems(String[] pArray) {
		DefaultComboBoxModel model = (DefaultComboBoxModel) getModel();
		int selected = model.getIndexOf(model.getSelectedItem());
		selected = (selected < 0) ? 0 : selected;
		model.removeAllElements();
		for (String tStr : pArray) {
			model.addElement(tStr);
		}
		model.setSelectedItem(pArray[selected]);
		setPopupWidth(getPopupWidth());
	}

	private class MyPopupMenuListener implements PopupMenuListener {

		public void popupMenuCanceled(PopupMenuEvent e) {
			// nicht benötigt
		}

		public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
			((ChangeableSteppedComboBox) e.getSource()).changeItems(invisible);
		}

		public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
			// nicht benötigt
		}
	}

	private class MyComboBoxUI extends WindowsComboBoxUI {

		protected ComboPopup createPopup() {
			BasicComboPopup tPopup = new BasicComboPopup(comboBox) {
				private static final long serialVersionUID = 1L;

				public void show() {

					((ChangeableSteppedComboBox) comboBox).changeItems(visible);

					Dimension tPopupSize = ((ChangeableSteppedComboBox) comboBox)
							.getPopupSize();

					tPopupSize.setSize(tPopupSize.width + 5,
							getPopupHeightForRowCount(comboBox
									.getMaximumRowCount()));

					Rectangle popupBounds = computePopupBounds(0, comboBox
							.getBounds().height, tPopupSize.width,
							tPopupSize.height);

					scroller.setMaximumSize(popupBounds.getSize());
					scroller.setPreferredSize(popupBounds.getSize());
					scroller.setMinimumSize(popupBounds.getSize());
					list.invalidate();
					int selectedIndex = comboBox.getSelectedIndex();
					if (selectedIndex == -1) {
						list.clearSelection();
					} else {
						list.setSelectedIndex(selectedIndex);
					}
					list.ensureIndexIsVisible(list.getSelectedIndex());
					setLightWeightPopupEnabled(comboBox
							.isLightWeightPopupEnabled());

					show(comboBox, popupBounds.x, popupBounds.y);
				}
			};
			tPopup.getAccessibleContext().setAccessibleParent(comboBox);
			return tPopup;
		}
	}

}
 
die festlegung auf das Win-LAF ist eigentlich gegen den sinn der plattform-unabhängigkeit und würde auf nicht-win systemen zu einer LAFNotFoundException führen was deine klasse damit unbrauchbar macht
hier wäre eine default-LAF - implementation vorteilhafter ...
das setzen des LAF würde ich dann in die main-klasse setzen *oder wo auch immer dein container definiert wird* und an diesem punkt vorher auf die verfügbarkeit prüfen ...
so können auch nutzer vom OpenJava deine klasse nutzen *dazu müsste noch sun.font.FontDesignMetrics und dessen verwendung angepasst werden*
 
danke für die info SPiKEe, werde mich wenn ich zeit habe mal daran setzen und die klasse ein bisschen aufhübschen
aber sie dient ja momentan nur zum testen für einen prototyp, wofür sie allemal ausreicht^^
 
Zurück