JCombobox with JMenuBar (as drop down menu)

Hello, i'm trying to make a new component (as generic as possible) to display a tree structure in a combo-like style.

So i finally choose a JTextfield to display the current item + a JMenuBar with Menu and MenuItem generated from a TreeModel (i'm not sure this is the better choice to make, but tha's not my present problem).

2 questions :

1) am I reinventing the wheel ?

2) i've got a problem of pack when displaying the compent and i don't find where.

Thanks. Cyril.

--

So, the code... two main classes : TreeComboBox + ArrowMenu

the TreeComboBox :

package fr.emanation.util.gui.treeComboBox;

import javax.swing.*;

import javax.swing.tree.TreeModel;

import java.awt.*;

import java.awt.event.FocusListener;

publicclass TreeComboBox<TNode>extends JPanel

{

private TNode theSelectedNode;

private ArrowMenuBar theMenuBar;

private JTextField theTextField;

privateint theCompactWidth;

public TreeComboBox(TreeModel aTreeModel)

{

new BorderLayout(0, 0);

theTextField =new JTextField();

theTextField.setEditable(true);

theTextField.setBackground(Color.white);

setFocusable(false);

add(theTextField, BorderLayout.CENTER);

MyArrowMenuInvoker anInvoker =new MyArrowMenuInvoker();

theMenuBar =new ArrowMenuBar<TNode>(anInvoker, aTreeModel);

JPanel menuBarPanel =new JPanel(new BorderLayout(0, 0));

menuBarPanel.add(theMenuBar, BorderLayout.CENTER);

add(menuBarPanel, BorderLayout.EAST);

}

public TNode getNode()

{

return (TNode) theSelectedNode;

}

publicvoid setSelectedNode(TNode aNode)

{

theSelectedNode = aNode;

theTextField.setText(aNode.toString());

}

public TreeModel getModel()

{

return theMenuBar.getModel();

}

public JComponent[] getFocusableComponents()

{

returnnew JComponent[]{theTextField, theMenuBar};

}

//-- JComponent overriden methods

public Dimension getMinimumSize()

{

final Dimension minSize = super.getMinimumSize();

minSize.width = theCompactWidth;

return minSize;

}

publicvoid setCompactWidth(finalint aCompactWidth)

{

theCompactWidth = aCompactWidth;

}

publicvoid setPreferredSize(Dimension aSize)

{

super.setPreferredSize(aSize);

if (theTextField !=null)

{

theTextField.setPreferredSize(aSize);

}

}

publicvoid setForeground(Color fg)

{

super.setForeground(fg);

if (theMenuBar !=null)

{

for (int index = 0; index < theMenuBar.getComponentCount(); index++)

{

theMenuBar.getComponents()[index].setForeground(fg);

}

}

if (theTextField !=null)

{

theTextField.setForeground(fg);

}

}

publicvoid setBackground(Color bg)

{

super.setBackground(bg);

if (theMenuBar !=null)

{

for (int index = 0; index < theMenuBar.getComponentCount(); index++)

{

theMenuBar.getComponents()[index].setBackground(bg);

}

}

if (theTextField !=null)

{

theTextField.setBackground(bg);

}

}

publicvoid setFont(Font aFont)

{

super.setFont(aFont);

if (theMenuBar !=null)

{

theMenuBar.setFont(aFont);

}

if (theTextField !=null)

{

theTextField.setFont(aFont);

}

}

publicvoid setToolTipText(String aToolTip)

{

super.setToolTipText(aToolTip);

if (theTextField !=null)

{

theTextField.setToolTipText(aToolTip);

}

}

publicvoid setEnabled(finalboolean bEnabled)

{

super.setEnabled(bEnabled);

if (theTextField !=null)return;

{

theTextField.setEnabled(bEnabled);

if (bEnabled)

{

theTextField.setBackground(Color.WHITE);

}

else

{

JLabel tmpLabel =new JLabel();

tmpLabel.setEnabled(false);

theTextField.setBackground(tmpLabel.getBackground());

}

}

if (theMenuBar !=null)

{

theMenuBar.setEnabled(bEnabled);

}

}

publicsynchronizedvoid addFocusListener(FocusListener l)

{

super.addFocusListener(l);

if (theMenuBar !=null)

{

theMenuBar.addFocusListener(l);

}

if (theTextField !=null)

{

theTextField.addFocusListener(l);

}

}

publicsynchronizedvoid removeFocusListener(FocusListener l)

{

super.removeFocusListener(l);

if (theMenuBar !=null)

{

theMenuBar.removeFocusListener(l);

}

if (theTextField !=null)

{

theTextField.removeFocusListener(l);

}

}

publicboolean isFocusOwner()

{

if (theMenuBar ==null || theTextField ==null)return super.isFocusOwner();

boolean bM = (theMenuBar ==null) && theMenuBar.isFocusOwner();

boolean bT = (theTextField ==null) && theTextField.isFocusOwner();

return (bM || bT);

}

//-- inner classes

privateclass MyArrowMenuInvokerimplements IArrowMenuInvoker<TNode>

{

public Component getComponent()

{

return theTextField;

}

publicvoid setNode(TNode aNode)

{

setSelectedNode(aNode);

}

}

}

the ArrowMenuBar :

package fr.emanation.util.gui.treeComboBox;

import javax.swing.*;

import javax.swing.border.EtchedBorder;

import javax.swing.plaf.UIResource;

import javax.swing.tree.TreeModel;

import java.awt.*;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

publicclass ArrowMenuBar<TNode>extends JMenuBar

{

private NodeMenu theMenu;

private TreeModel theModel;

private IArrowMenuInvoker<TNode> theInvoker;

public ArrowMenuBar(IArrowMenuInvoker<TNode> anInvoker, TreeModel aModel)

{

super();

theModel = aModel;

theInvoker = anInvoker;

TNode root = (TNode) theModel.getRoot();

if (!theModel.isLeaf(root))

{

theMenu =new ArrowMenu(root);

theMenu.setBackground(new JPanel().getBackground());

}

MenuItemListener listener =new MenuItemListener();

setListener(theMenu, listener);

add(theMenu);

}

privatevoid setListener(JMenuItem anItem, ActionListener aListener)

{

if (anIteminstanceof JMenu)

{

JMenu menu = (JMenu) anItem;

int n = menu.getItemCount();

for (int index = 0; index < n; index++)

{

setListener(menu.getItem(index), aListener);

}

}

elseif (anItem !=null)

{

// null means separator

anItem.addActionListener(aListener);

}

}

public TreeModel getModel()

{

return theModel;

}

public Action getLaunchArrowMenuBarAction()

{

returnnew LaunchArrowMenuBarAction();

}

//-- overrides JComponent

public Dimension getPreferredSize()

{

return theMenu.getPreferredSize();

}

private Dimension getItemSize(JMenu aMenu)

{

Dimension dimension =new Dimension(0, 0);

int n = aMenu.getItemCount();

for (int index = 0; index < n; index++)

{

Dimension itemD;

JMenuItem item = aMenu.getItem(index);

if (iteminstanceof JMenu)

{

itemD = getItemSize((JMenu) item);

}

elseif (item !=null)

{

itemD = item.getPreferredSize();

}

else

{

itemD =new Dimension(0, 0);// separator

}

dimension.width = Math.max(dimension.width, itemD.width);

dimension.height = Math.max(dimension.height, itemD.height);

}

return dimension;

}

// inner classes

privateclass LaunchArrowMenuBarActionextends AbstractAction

{

public LaunchArrowMenuBarAction()

{

super("...");

}

publicvoid actionPerformed(ActionEvent e)

{

if (e.getActionCommand() =="Launch")

{

System.out.println("Launch");

}

}

}

privateclass MenuItemListenerimplements ActionListener

{

publicvoid actionPerformed(ActionEvent anEvent)

{

NodeMenuItem item = (NodeMenuItem) anEvent.getSource();

theInvoker.setNode(item.getNode());

theMenu.requestFocus();

}

}

privateclass NodeMenuextends JMenu

{

private TNode theNode;

public NodeMenu(TNode aNode)

{

this(aNode.toString(), aNode);

}

public NodeMenu(String theText, TNode aNode)

{

super(theText);

theNode = aNode;

add(new NodeMenuItem("[.]", aNode));

for (int index = 0; index < theModel.getChildCount(aNode); index++)

{

TNode childNode = (TNode) theModel.getChild(aNode, index);

if (theModel.isLeaf(childNode))

{

add(new NodeMenuItem(childNode));

}

else

{

add(new NodeMenu(childNode));

}

}

}

publicvoid setNode(TNode aNode)

{

theNode = aNode;

}

public TNode getNode()

{

return theNode;

}

}

privateclass NodeMenuItemextends JMenuItem

{

private TNode theNode;

public NodeMenuItem(TNode aNode)

{

super(aNode.toString());

theNode = aNode;

}

public NodeMenuItem(String aText, TNode aNode)

{

super(aText);

theNode = aNode;

}

public TNode getNode()

{

return theNode;

}

}

privateclass ArrowMenuextends NodeMenu

{

//private ArrowIcon theIconRenderer;

private Color shadow = UIManager.getColor("controlShadow");

private Color darkShadow = UIManager.getColor("controlDkShadow");

private Color highlight = UIManager.getColor("controlLtHighlight");

public ArrowMenu(TNode aNode)

{

super("", aNode);

//theIconRenderer = new ArrowIcon(SwingConstants.SOUTH, true);

setBorder(new EtchedBorder());

//setIcon(new BlankIcon(null, 11));

setHorizontalTextPosition(JButton.LEFT);

setFocusPainted(true);

}

publicvoid paint(Graphics g)

{

Color origColor;

boolean isEnabled;

int w, h, size;

w = getSize().width;

h = getSize().height;

origColor = g.getColor();

isEnabled = isEnabled();

g.setColor(getBackground());

g.fillRect(1, 1, w - 2, h - 2);

/// Draw the proper Border

if (getBorder() !=null && !(getBorder()instanceof UIResource))

{

paintBorder(g);

}

else

{

// Using the background color set above

g.drawLine(0, 0, 0, h - 1);

g.drawLine(1, 0, w - 2, 0);

g.setColor(highlight);// inner 3D border

g.drawLine(1, 1, 1, h - 3);

g.drawLine(2, 1, w - 3, 1);

g.setColor(shadow);// inner 3D border

g.drawLine(1, h - 2, w - 2, h - 2);

g.drawLine(w - 2, 1, w - 2, h - 3);

g.setColor(darkShadow);// black drop shadow __|

g.drawLine(0, h - 1, w - 1, h - 1);

g.drawLine(w - 1, h - 1, w - 1, 0);

}

// If there's no room to draw arrow, bail

if (h < 5 || w < 5)

{

g.setColor(origColor);

return;

}

// Draw the arrow

size = Math.min((h - 4) / 3, (w - 4) / 3);

size = Math.max(size, 2);

paintTriangle(g, (w - size) / 2, (h - size) / 2,

size, SwingConstants.SOUTH, isEnabled);

// Reset the Graphics back to it's original settings

g.setColor(origColor);

}

public Dimension getPreferredSize()

{

returnnew Dimension(16, 16);

}

public Dimension getMinimumSize()

{

returnnew Dimension(5, 5);

}

public Dimension getMaximumSize()

{

returnnew Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);

}

publicvoid paintTriangle(Graphics g,int x,int y,int size,

int direction,boolean isEnabled)

{

Color oldColor = g.getColor();

int mid, i, j;

j = 0;

size = Math.max(size, 2);

mid = (size / 2) - 1;

g.translate(x, y);

if (isEnabled)

{

g.setColor(darkShadow);

}

else

{

g.setColor(shadow);

}

switch (direction)

{

case NORTH:

for (i = 0; i < size; i++)

{

g.drawLine(mid - i, i, mid + i, i);

}

if (!isEnabled)

{

g.setColor(highlight);

g.drawLine(mid - i + 2, i, mid + i, i);

}

break;

case SOUTH:

if (!isEnabled)

{

g.translate(1, 1);

g.setColor(highlight);

for (i = size - 1; i >= 0; i--)

{

g.drawLine(mid - i, j, mid + i, j);

j++;

}

g.translate(-1, -1);

g.setColor(shadow);

}

j = 0;

for (i = size - 1; i >= 0; i--)

{

g.drawLine(mid - i, j, mid + i, j);

j++;

}

break;

case WEST:

for (i = 0; i < size; i++)

{

g.drawLine(i, mid - i, i, mid + i);

}

if (!isEnabled)

{

g.setColor(highlight);

g.drawLine(i, mid - i + 2, i, mid + i);

}

break;

case EAST:

if (!isEnabled)

{

g.translate(1, 1);

g.setColor(highlight);

for (i = size - 1; i >= 0; i--)

{

g.drawLine(j, mid - i, j, mid + i);

j++;

}

g.translate(-1, -1);

g.setColor(shadow);

}

j = 0;

for (i = size - 1; i >= 0; i--)

{

g.drawLine(j, mid - i, j, mid + i);

j++;

}

break;

}

g.translate(-x, -y);

g.setColor(oldColor);

}

}

}

[28464 byte] By [moshikaa] at [2007-10-3 3:51:39]
# 1

Darkness and blindness are away !

First line of the constructor :

public TreeComboBox(TreeModel aTreeModel)

{

new BorderLayout(0, 0);

...

}

I will reborn as a pumpkin !

moshikaa at 2007-7-14 21:49:18 > top of Java-index,Desktop,Core GUI APIs...