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.
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.
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)
3. XJPopupMenu.java (This is the heart of Scrollable JPopupMenu code)
4. XConstant.java (Interface containing commonly used constants)
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;
}
}
|
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