# Drop-down menü in Toolbar Button



## jawohl (17. Jan 2005)

Hat jemand eine Ahnung wie ich dies realisieren kann.






ich habs mal mit jtogglebutton und jpopupmenu versucht hat aber nicht funktioniert, wobei das nicht heißen soll dass es überhaupt nicht geht. Wäre für jede Hilfe sehr dankbar da ich es für eine Diplomarbeit brauchen würde. Dankeschön.


----------



## Sky (17. Jan 2005)

Also, 'jtogglebutton' und 'jpopupmenu' halte ich mal für keinen schlechten Anfang... was ging denn an dieser Lösung nicht?? Zeig doch mal den Code, vielleicht ist's ja nur ne Kleinigkeit.


----------



## AlArenal (18. Jan 2005)

Ich habs auch mal so gemacht und das funzt. Was ich bisher noch nicht gefunden habe ist so ein Button, wie man ihn u.a. in Office-Produkten oder im JBuilder findet, der nochmal unterteilt ist. Wo der eigentliche Button ne eigene Action hat und der Button-Teil mit dem Pfeil nochmal ne eigene Action (eben das Popup-Menü).


----------



## jawohl (18. Jan 2005)

Ja ob ich dann mit dem Pfeil nochmal seperat eine aktion hab ist egal. Mir ist nur wichtig dass ich ein drop-down menü bekomm.

ja also es scheitert daran dass ich nicht genau weiß wie ich den Button mit dem Drop-down menü verbinden soll, dass er dann auch wirklich das Teil ausklappt. 

Wenn mir jemand ein kleines Code beispiel geben könnte wäre es super.


----------



## AlArenal (18. Jan 2005)

Na auf den Button legste ganz normal deinen Event-Handler. Darin sagste dann er soll das Popup-Menü aufmachen. Wenn button der gewünschte Button ist und popup das Popup-Menü, dann öffnet folgende Zeile in dem Event-Handler das Popup-Menü direkt unter den Button, bündig mit der linken Kante des Buttons abschließend. Und da sich das Ganze direkt auf den Button bezieht und nicht auf irgendwelche Koordinaten, wird das Menü auch beim Verschieben des Fensters mitverschoben.


```
popup.show(button, 0, button.getHeight());
```


----------



## Beni (18. Jan 2005)

Ich hab noch den Code zu solch einem Button, vielleicht nützt er dir was (ist leider Bestandteil eines Progis, und nicht ganz soooo allgemein geschrieben).


```
/*
 * Created on 05.07.2004
 */
package beziermanager.gui;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Vector;

import javax.swing.ButtonGroup;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JToggleButton;
import javax.swing.SwingUtilities;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;

import beziermanager.Resources;
import beziermanager.event.DropDownButtonListener;

/**
 * @author Benjamin Sigg
 * @version 1.0
 */
public class DropDownButton extends JComponent {
	private JToggleButton button;
	private JButton dropButton;
	private JPopupMenu menu;
	private int dropWidth = 5;
	
	private Vector<DropDownButtonListener> listeners = new Vector<DropDownButtonListener>();
	private Listener listener = new Listener();
	
	private Capsel selection = null;
	private Vector<Capsel> values = new Vector<Capsel>();
	
	private ButtonGroup group = new ButtonGroup();
	
	// gibt an, ob ein Event abgeschossen werden soll
	private boolean fire = true;
	
	private static final Insets NULL_INSETS = new Insets( 0, 0, 0, 0 );
	
	public DropDownButton() {
		button = new JToggleButton(){
			public void paint( Graphics g ){
				super.paint( g );
				
				if( dropButton != null ){
					g = g.create( dropButton.getX(), dropButton.getY(), dropButton.getWidth(), dropButton.getHeight() );
					dropButton.paint( g );
				}
			}
		};
		button.addItemListener( new ItemListener(){
			public void itemStateChanged(ItemEvent e) {
				if( !button.isSelected() ){
					menu.setVisible( false );
					fireAction();
				}
			}
		});
		
		button.addMouseListener( new MouseAdapter(){
			public void mouseReleased(MouseEvent e) {
				if( button.isSelected() )
					button.setSelected( false );
			}
		});
		
		dropButton = new JButton( Resources.getIcon( "menu button" ) ){
			public void paint( Graphics g ){
				Icon icon = getIcon();
				if( icon != null ){
					int x = (getWidth() - icon.getIconWidth()) / 2;
					int y = (getHeight() - icon.getIconHeight()) / 2;
					icon.paintIcon( this, g, x, y );
				}
			}
		};
		
		setLayout( null );
		
		dropButton.setBorder( null );
		dropButton.setOpaque( false );
		add( dropButton );
		
		add( button );
		
		menu = new JPopupMenu();
		
		dropButton.addActionListener( new ActionListener(){
			public void actionPerformed( ActionEvent e ) {
				menu.show( dropButton, - dropButton.getX(), dropButton.getHeight() );
				button.setSelected( true );
			}
		});
		
		menu.addPopupMenuListener( new PopupMenuListener(){

			public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
			}

			public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
			}

			public void popupMenuCanceled(PopupMenuEvent e) {
				fire = false;
				button.setSelected( false );
				fire = true;
			}
			
		});
		
		setIcon( null );
	}
	
	
	public void setIcon( Icon defaultIcon ) {
		button.setIcon( new ButtonIcon( defaultIcon ));
	}
	
	private void setSelection( Capsel capsel ){
		selection = capsel;
		if( capsel == null ){
			setIcon( Resources.EMPTY_ICON );
			button.setToolTipText( "" );
		}
		else{
			setIcon( capsel.icon );
			button.setToolTipText( capsel.text );
			capsel.menuItem.setSelected( true );
		}
	}
	
	public Object getSelection(){
		if( selection == null )
			return null;
		else
			return selection.value;
	}
	
	public void setSelection( Object value ){
		if( value == null ){
			if( selection != null )
				selection.menuItem.setSelected( false );
			setSelection( null );
		}
		else{
			Capsel capsel = find( value );
			if( capsel == null ){
				if( selection != null )
					selection.menuItem.setSelected( false );
				setSelection( null );
			}
			else{
				setSelection( capsel );
			}
		}
	}
	
	public Insets getInsets() {
		Insets insets = button.getInsets();
		return insets == null ? NULL_INSETS : insets;
	}
	
	/**
	 * Gibt die Anzahl Werte zurück, welche von diesem DropDownButton
	 * angezeigt werden.
	 * @return Die Anzahl Werte
	 */
	public int getItemCount(){
		return values.size();
	}
	
	public Object getItem( int index ){
		return values.get( index ).value;
	}
	
	public synchronized void insertItem( Icon icon, String text, Object value, int index ){
		Capsel capsel = new Capsel( icon, text, value );
		values.insertElementAt( capsel, index );
		JRadioButtonMenuItem item = new JRadioButtonMenuItem( text, icon, false );
		capsel.menuItem = item;
		menu.insert( item, index );
		group.add( item );
		
		if( selection == null )
			setSelection( capsel );
		
		item.addItemListener( listener );
		item.addActionListener( listener );
	}
	
	public void setIcon( Object value, Icon icon ){
		Capsel capsel = find( value );
		capsel.icon = icon;
		capsel.menuItem.setIcon( icon );
		if( selection == capsel )
			setIcon( icon );
	}
	
	public void setIcon( int index, Icon icon ){
		Capsel capsel = values.get( index );
		capsel.icon = icon;
		capsel.menuItem.setIcon( icon );
		if( selection == capsel )
			setIcon( icon );		
	}
	
	public void setText( Object value, String text ){
		Capsel capsel = find( value );
		capsel.text = text;
		capsel.menuItem.setText( text );
		if( selection == capsel )
			button.setToolTipText( text );		
	}
	
	public void setText( int index, String text ){
		Capsel capsel = values.get( index );
		capsel.text = text;
		capsel.menuItem.setText( text );
		if( selection == capsel )
			button.setToolTipText( text );	
	}
	
	public void removeItem( Object value ){
		Capsel capsel = find( value );
		if( capsel != null ){
			if( capsel == selection )
				setSelection( null );
			
			menu.remove( capsel.menuItem );
			capsel.menuItem.removeItemListener( listener );
			capsel.menuItem.removeActionListener( listener );
			group.remove( capsel.menuItem );
			values.remove( capsel );
		}
	}
	public void removeItem( int index ){
		Capsel capsel = values.remove( index );

		if( capsel == selection )
			setSelection( null );
			
		menu.remove( capsel.menuItem );
		capsel.menuItem.removeItemListener( listener );
		group.remove( capsel.menuItem );
		values.remove( capsel );
	}

	private Capsel find( Object value ){
		for( int i = 0, n = values.size(); i<n; i++ ){
			Capsel c = values.get( i );
			if( c.value == value )
				return c;
		}
		
		for( int i = 0, n = values.size(); i<n; i++ ){
			Capsel c = values.get( i );
			if( c.value.equals( value ) )
				return c;
		}
		
		return null;
	}
	
	private Capsel find( JRadioButtonMenuItem item ){
		for( int i = 0, n = values.size(); i<n; i++ ){
			Capsel c = values.get( i );
			if( c.menuItem == item )
				return c;
		}
		
		return null;
	}
	
	public void addDropDownButtonListener( DropDownButtonListener l ){
		listeners.add( l );
	}
	public void removeDropDownButtonListener( DropDownButtonListener l ){
		listeners.remove( l );
	}
	
	protected void fireAction(){
		if( fire )
			for( DropDownButtonListener x : listeners )
				x.actionPerformed( this, selection.value );
	}
	
	public void updateUI() {
		super.updateUI();
		if( dropButton != null )
			dropButton.updateUI();
		
		if( menu!= null )
			SwingUtilities.updateComponentTreeUI( menu );
	}
	
	public Dimension getMinimumSize() {
		return button.getMinimumSize();
	}
	
	public Dimension getPreferredSize() {
		return button.getPreferredSize();
	}
	
	public void paint( Graphics g ){
		if( button != null )
			button.paint( g );
	}
	
	public void doLayout() {
		if( button != null ){
			button.setBounds( 0, 0, getWidth(), getHeight() );
			
		}
		
		if( dropButton != null ){
			Insets insets = getInsets();
			
			dropButton.setBounds( getWidth()-dropWidth-insets.right , insets.top,
					dropWidth+insets.right, getHeight()-insets.top-insets.bottom );
		}
	}
	
	private class Listener implements ActionListener, ItemListener{
		public void actionPerformed(ActionEvent e) {
			button.setSelected( false );
		}
		
		public void itemStateChanged( ItemEvent e ) {
			JRadioButtonMenuItem item = (JRadioButtonMenuItem)e.getSource();
			if( item.isSelected() ){
				Capsel capsel = find( item );
				setIcon( capsel.icon );
				selection = capsel;
				button.setSelected( false );
			}
		}
	}
	
	private class Capsel{
		public Icon icon;
		public String text;
		public Object value;
		public JRadioButtonMenuItem menuItem;
		
		public Capsel( Icon icon, String text, Object value ){
			this.icon = icon;
			this.text = text;
			this.value = value;
		}
		
		public Capsel(){
		}
	}
	
	private class ButtonIcon implements Icon{
		private Icon original;
		
		public ButtonIcon( Icon original ){
			this.original = original;
		}
		
		public int getIconHeight() {
			return original == null ? 16 : original.getIconHeight();
		}
		
		public int getIconWidth() {
			return original == null ? 16 : original.getIconWidth() + (getInsets().right + dropWidth) / 2;
		}
		public void paintIcon( Component c, Graphics g, int x, int y ) {
			if( original != null )
				original.paintIcon(c, g, x, y);
		}
	}
}
```


```
/*
 * Created on 06.07.2004
 */
package beziermanager.event;

import beziermanager.gui.DropDownButton;

/**
 * @author Benjamin Sigg
 * @version 1.0
 */
public interface DropDownButtonListener {
	/**
	 * Wird aufgerufen, wenn der User auf den Button geklickt hat, oder ein
	 * neues Element selektiert wurde.
	 * @param source Der DropDownButton, der das Ereignis ausgelöst hat.
	 * @param selection Die Selektion des Buttons oder null, sollte nichts
	 * selektiert sein.
	 */
	public void actionPerformed( DropDownButton source, Object selection );
}
```


----------



## AlArenal (18. Jan 2005)

Soviel Code und so wenig Kommentar


----------



## TheDragonMaster (18. Jan 2005)

Ich arbeite gerade an einer simplen Version eines solchen Buttons.
Habe allerdings erst ein paar Minuten investiert, es fehlt also noch de r Pfeil an der Seite (ich bin mir auch noch nicht im klaren welche Methode ich dafür verwenden soll, die eigentlich korrekte, d.h. per ButtonUI, oder eine etwas fiesere per paintComponent - die einfacher und portabler, dafür aber unpassender wäre).

Hier ist mein bisheriger Code (natürlich ziehmlich unschön - ist halt nur Prototyp):

```
/*
 * This file is part of PgsSwing - Utilities and components for Swing
 * Copyright (c) 2004 Patrick Gotthardt
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package com.pagosoft.swing;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.plaf.*;
import javax.swing.plaf.metal.*;

public class JPopupButton extends JButton {
	private JPopupMenu menu;
	private boolean popupVisible;
	
	public JPopupButton() {
		super();
		_init();
	}
	
	public JPopupButton(String label) {
		super(label);
		_init();
	}
	
	public JPopupButton(Icon ico) {
		super(ico);
		_init();
	}
	
	public JPopupButton(String label, Icon ico) {
		super(label, ico);
		_init();
	}
	
	private void _init() {
		super.setModel(new DefaultButtonModel() {
			public boolean isPressed() {
				return isPopupVisible() || super.isPressed();
			}
			
			public boolean isArmed() {
				return isPopupVisible() || super.isArmed();
			}
			
			public boolean isRollover() {
				return isPopupVisible() || super.isRollover();
			}
		});
		
		popupVisible = false;
		
		menu = new JPopupMenu();
		menu.addPopupMenuListener(new PopupListener(this));
		
		addActionListener(new PopupHandler(this, menu));
	}
	
	public JPopupMenu getMenu() {
		return menu;
	}
	
	/**
	 * Even if this method is public,
	 * don't use it (except you're going to create a
	 * UI or something like that...)!
	 */
	public void setPopupVisible(boolean isVisible) {
		popupVisible = isVisible;
	}
	
	public boolean isPopupVisible() {
		return popupVisible;
	}
	
	private class PopupHandler implements ActionListener {
		private JPopupButton button;
		private JPopupMenu menu;
		
		public PopupHandler(JPopupButton b, JPopupMenu m) {
			button = b;
			menu = m;
		}
		
		public void actionPerformed(ActionEvent e) {
			menu.show(button, 0, button.getHeight());
		}
	}
	
	private class PopupListener implements PopupMenuListener {
		JPopupButton button;
		public PopupListener(JPopupButton b) {
			button = b;
		}
		
		public void popupMenuCanceled(PopupMenuEvent e) {}
		public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
			button.setPopupVisible(false);
		}
		public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
			button.setPopupVisible(true);
		}
	}
}
```

Anwendungsbeispiel:

```
JPopupButton pb = new JPopupButton("Click");
JPopupMenu menu = pb.getMenu();
menu.add(new JMenuItem("Test"));
menu.add(new JMenuItem("Test2"));
menu.add(new JMenuItem("Test3"));
menu.add(new JMenuItem("Test4"));
```






Eigenwerbung ist nicht erlaubt, deswegen schreibe ich hier mal nicht hin, wo man die fertige Komponente herbekommt - wenn sie denn fertig ist. 

Anmerkung: Die Variante von Beni ist ebenfalls nicht schlecht, aber für meinen Geschmack sollte ein Button ein Button sein und kein JComponent.
Meine Version hat aktuell allerdings noch nicht die Möglichkeit - und wird sie auch in dieser Form nicht bekommen - zwischen Klick auf den (aktuell noch nicht existierenden) Pfeil und Klick auf den Button zu unterscheiden.
Das werde ich später in Form eines von JPopupButton abgeleiteten Buttons (JSplitButton o.ä.) realisieren.


----------



## jawohl (18. Jan 2005)

AlArenal hat gesagt.:
			
		

> Na auf den Button legste ganz normal deinen Event-Handler. Darin sagste dann er soll das Popup-Menü aufmachen. Wenn button der gewünschte Button ist und popup das Popup-Menü, dann öffnet folgende Zeile in dem Event-Handler das Popup-Menü direkt unter den Button, bündig mit der linken Kante des Buttons abschließend. Und da sich das Ganze direkt auf den Button bezieht und nicht auf irgendwelche Koordinaten, wird das Menü auch beim Verschieben des Fensters mitverschoben.
> 
> 
> ```
> ...



Super, danke. Jetzt hats funktioniert.


----------

