SCROLLABLE JPOPUPMENU
Java Swing Tutorial Explaining the Scrollable Popup Menu Component. Scrollable JPopupMenu can be used in
any of the Java Applications.
I developed this as the popup menu can have so many menuitems that, they exceed the screen visible area
and would not be visible.
I needed a way to scroll through the menu items of the pop up menu to avoid this visibility problem.
any of the Java Applications.
I developed this as the popup menu can have so many menuitems that, they exceed the screen visible area
and would not be visible.
I needed a way to scroll through the menu items of the pop up menu to avoid this visibility problem.
SCROLLABLE POPUPMENU SOURCE CODE
Custom JButtons are placed on a JPanel. This JPanel is placed on JScrollPane which has a scrollbar.
These custom JButtons are nothing but menuitems. These menuitems can be checked and unchecked similar to JCheckBoxMenuItems.
These custom JButtons are nothing but menuitems. These menuitems can be checked and unchecked similar to JCheckBoxMenuItems.
My scrollable jpopupmenu source code contains 5 files.
1. JFramePopupMenu.java (Mainframe containing the button to invoke Scrollable popup menu)
2. XCheckedButton.java (Custom JButton which acts like a JCheckBoxMenuItem for the pop up menu.
This class provides a JCheckBoxMenuItrem Functionality, optionally working like a JMenuItem, primarily
used with XJPopupMenu. Rationale for development of this component was the inability of a JMenuItem to work
in a Scrollable Popup menu as in XJPopupMenu)
This class provides a JCheckBoxMenuItrem Functionality, optionally working like a JMenuItem, primarily
used with XJPopupMenu. Rationale for development of this component was the inability of a JMenuItem to work
in a Scrollable Popup menu as in XJPopupMenu)
3. XJPopupMenu.java (This is the heart of Scrollable JPopupMenu code)
4. XConstant.java (Interface containing commonly used constants)
5. check.gif
6. menu_spacer.gif
Here is a source code showing, how to create a java swing JPopupMenu with a vertical scrollbar:
1. JFramePopupMenu.java
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class JFramePopupMenu extends JFrame {
private JPanel jContentPane = null;
private JButton jbnPopup = null;
private JTextField jtfNumOfMenus = null;
private JLabel lblNumElem = null;
private XJPopupMenu scrollablePopupMenu = new XJPopupMenu(this);
private JButton getBtnPopup() {
if (jbnPopup == null) {
jbnPopup = new JButton();
jbnPopup.setText("View Scrollable popup menu ");
int n = Integer.parseInt(getTxtNumElem().getText());
for (int i=0;i<n;i++){
XCheckedButton xx = new XCheckedButton(" JMenuItem " + (i+1));
xx.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
System.out.println( e );
scrollablePopupMenu.hidemenu();
}
});
// Add Custom JSeperator after 2nd and 7th MenuItem.
if(i == 2 || i == 7){
scrollablePopupMenu.addSeparator();
}
scrollablePopupMenu.add(xx);
}
jbnPopup.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
Component source = (Component) e.getSource();
scrollablePopupMenu.show(source, e.getX(), e.getY());
}
});
}
return jbnPopup;
}
private JTextField getTxtNumElem() {
if (jtfNumOfMenus == null) {
jtfNumOfMenus = new JTextField();
jtfNumOfMenus.setColumns(3);
jtfNumOfMenus.setText("60");
}
return jtfNumOfMenus;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFramePopupMenu thisClass = new JFramePopupMenu();
thisClass.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
thisClass.setVisible(true);
}
});
}
public JFramePopupMenu() {
super();
initialize();
}
private void initialize() {
this.setSize(274, 109);
this.setContentPane(getJContentPane());
this.setTitle(" Scrollable JPopupMenu ");
}
private JPanel getJContentPane() {
if (jContentPane == null) {
lblNumElem = new JLabel();
FlowLayout flowLayout = new FlowLayout();
flowLayout.setHgap(8);
flowLayout.setVgap(8);
jContentPane = new JPanel();
jContentPane.setLayout(flowLayout);
jContentPane.add(getBtnPopup(), null);
jContentPane.add(lblNumElem, null);
jContentPane.add(getTxtNumElem(), null);
}
return jContentPane;
}
}
2. XCheckedButton.java
import java.awt.Color; import java.awt.event.ItemEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JToggleButton; import javax.swing.SwingConstants; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicButtonUI; /** * @author balajihe * */ public class XCheckedButton extends JButton { // Icon to be used to for the Checked Icon of the Button private static ImageIcon checkedIcon; /** * These colors are required in order to simulate the JMenuItem's L&F */ public static final Color MENU_HIGHLIGHT_BG_COLOR = UIManager.getColor ("MenuItem.selectionBackground"); public static final Color MENU_HIGHLIGHT_FG_COLOR = UIManager.getColor ("MenuItem.selectionForeground"); public static final Color MENUITEM_BG_COLOR = UIManager.getColor ("MenuItem.background"); public static final Color MENUITEM_FG_COLOR = UIManager.getColor ("MenuItem.foreground"); // This property if set to false, will result in the checked Icon not being // displayed when the button is selected private boolean displayCheck = true; public XCheckedButton() { super(); init(); } public XCheckedButton(Action a) { super(a); init(); } public XCheckedButton(Icon icon) { super(icon); init(); } public XCheckedButton(String text, Icon icon) { super(text, icon); init(); } public XCheckedButton(String text) { super(text); init(); } /** * Initialize component LAF and add Listeners */ private void init() { MouseAdapter mouseAdapter = getMouseAdapter(); // Basically JGoodies LAF UI for JButton does not allow Background color to be set. // So we need to set the default UI, ComponentUI ui = BasicButtonUI.createUI(this); this.setUI(ui); setBorder(BorderFactory.createEmptyBorder(3, 0, 3, 2)); setMenuItemDefaultColors(); // setContentAreaFilled(false); setHorizontalTextPosition(SwingConstants.RIGHT); setHorizontalAlignment(SwingConstants.LEFT); // setModel(new JToggleButton.ToggleButtonModel()); setModel(new XCheckedButtonModel()); setSelected(false); this.addMouseListener(mouseAdapter); } private void setMenuItemDefaultColors() { XCheckedButton.this.setBackground(MENUITEM_BG_COLOR); XCheckedButton.this.setForeground(MENUITEM_FG_COLOR); } /** * @return */ private MouseAdapter getMouseAdapter() { return new MouseAdapter() { // For static menuitems, the background color remains the highlighted color, if this is not overridden public void mousePressed(MouseEvent e) { setMenuItemDefaultColors(); } public void mouseEntered(MouseEvent e) { XCheckedButton.this.setBackground(MENU_HIGHLIGHT_BG_COLOR); XCheckedButton.this.setForeground(MENU_HIGHLIGHT_FG_COLOR); } public void mouseExited(MouseEvent e) { setMenuItemDefaultColors(); } }; } /** * @param checkedFlag */ public void displayIcon(boolean checkedFlag) { if (checkedFlag && isDisplayCheck()) { if (checkedIcon == null) { checkedIcon = new ImageIcon("check.gif"); } this.setIcon(checkedIcon); } else { this.setIcon(XConstant.EMPTY_IMAGE_ICON); } this.repaint(); } private class XCheckedButtonModel extends JToggleButton.ToggleButtonModel { /* * Need to Override keeping the super code, else the check mark won't come */ public void setSelected(boolean b) { ButtonGroup group = getGroup(); if (group != null) { // use the group model instead group.setSelected(this, b); b = group.isSelected(this); } if (isSelected() == b) { return; } if (b) { stateMask |= SELECTED; } else { stateMask &= ~SELECTED; } // Send ChangeEvent fireStateChanged(); // Send ItemEvent fireItemStateChanged(new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED, this,this.isSelected() ? ItemEvent.SELECTED : ItemEvent.DESELECTED)); XCheckedButton.this.displayIcon(b); } } // Returns true if Button will display Checked Icon on Click. Default Behaviour is // to display a Checked Icon public boolean isDisplayCheck() { return displayCheck; } /** * Sets the property which determines whether a checked Icon should be displayed or not * Setting to false, makes this button display like a normal button * @param displayCheck */ public void setDisplayCheck(boolean displayCheck) { this.displayCheck = displayCheck; } }
3. XJPopupMenu.java
this.getToolkit().getScreenSize().height - this.getToolkit().getScreenInsets(jframe.getGraphicsConfiguration()).top - this.getToolkit().getScreenInsets(jframe.getGraphicsConfiguration()).bottom - 4)); super.add(scroll, BorderLayout.CENTER); // super.add(scroll); } public void show(Component invoker, int x, int y) { init(jframe); // this.pack(); panelMenus.validate(); int maxsize = scroll.getMaximumSize().height; int realsize = panelMenus.getPreferredSize().height; int sizescroll = 0; if (maxsize < realsize) { sizescroll = scroll.getVerticalScrollBar().getPreferredSize().width; } Scroll.setPreferredSize(new Dimension(scroll.getPreferredSize().width + sizescroll + 20, scroll.getPreferredSize().height)); this.pack(); this.setInvoker(invoker); if (sizescroll != 0) { //Set popup size only if scrollbar is visible this.setPopupSize(new Dimension(scroll.getPreferredSize().width + 20, scroll.getMaximumSize().height - 20)); } // this.setMaximumSize(scroll.getMaximumSize()); Point invokerOrigin = invoker.getLocationOnScreen() this.setLocation((int) invokerOrigin.getX() + x, (int) invokerOrigin.getY() + y); this.setVisible(true); } public void hidemenu() { if (this.isVisible()) { this.setVisible(false); } } public void add(AbstractButton menuItem) { // menuItem.setMargin(new Insets(0, 20, 0 , 0)); if (menuItem == null) { return; } panelMenus.add(menuItem); menuItem.removeActionListener(this); menuItem.addActionListener(this); if (menuItem.getIcon() == null) { menuItem.setIcon(EMPTY_IMAGE_ICON); } if (!(menuItem instanceof XCheckedButton)) { System.out.println(menuItem.getName()); } } public void addSeparator() { panelMenus.add(new XSeperator()); } public void actionPerformed(ActionEvent e) { this.hidemenu(); } public Component[] getComponents() { return panelMenus.getComponents(); } private static class XSeperator extends JSeparator { XSeperator() { ComponentUI ui = XBasicSeparatorUI.createUI(this); XSeperator.this.setUI(ui); } private static class XBasicSeparatorUI extends BasicSeparatorUI { public static ComponentUI createUI(JComponent c) { return new XBasicSeparatorUI(); } public void paint(Graphics g, JComponent c) { Dimension s = c.getSize(); if (((JSeparator) c).getOrientation() == JSeparator.VERTICAL) { g.setColor(c.getForeground()); g.drawLine(0, 0, 0, s.height); g.setColor(c.getBackground()); g.drawLine(1, 0, 1, s.height); } else // HORIZONTAL { g.setColor(c.getForeground()); g.drawLine(0, 7, s.width, 7); g.setColor(c.getBackground()); g.drawLine(0, 8, s.width, 8); } } } } }
4. XConstant.java
import javax.swing.Icon; import javax.swing.ImageIcon; public interface XConstant { public static final Icon EMPTY_IMAGE_ICON = new ImageIcon("menu_spacer.gif"); }
Note: Please use the 2 jgoodies jars present in the zip file for the jgoodies look and feel
No comments:
Post a Comment