Results 1 to 10 of 10
- 12-13-2010, 04:56 PM #1
Member
- Join Date
- Dec 2010
- Posts
- 7
- Rep Power
- 0
Adding a JPanel to a JMenu - Focus issues
Hi all,
I am working on a requirement and have come across something unexpected.
The expected behaviour when working with menu items is when adding a JMenuItems to a JMenu and making the Menu visible, moving the mouse over each of the items highlights that items and allows each to be selected.
However when I add a JPanel to a JMenu, and the JPanel contains the JMenuItems, these items are no longer highlighted or selectable. Further, when mousing over the contained JMenuItems, focus seems to be lost from the JMenu entirely and the popup disappears altogether.
I've constructed the following code to demonstrate this issue:
Java Code:import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.BoxLayout; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; public class TestMenuItems extends JFrame { private JPopupMenu _thePopup = new JPopupMenu(); public TestMenuItems() { this.setLayout( new BorderLayout() ); JPanel thePanel = new JPanel(); this.add( thePanel, BorderLayout.CENTER ); this.addMouseListener( new MouseAdapter(){ public void mousePressed(MouseEvent e) { _thePopup.show((Component)e.getSource(), e.getX(), e.getY()); } }); JMenu theMenu = new JMenu("Menu"); _thePopup.add( theMenu ); thePanel.setBackground( Color.BLUE ); thePanel.setLayout( new BorderLayout() ); JPanel theInnerPanel = new JPanel(); theInnerPanel.setLayout( new BoxLayout( theInnerPanel, BoxLayout.X_AXIS ) ); theInnerPanel.add( new JMenuItem("Press 1") ); theInnerPanel.add( new JMenuItem("Press 2") ); theMenu.add(theInnerPanel); theMenu.add(new JMenuItem("Press 3")); theMenu.add(new JMenuItem("Press 4")); } public static void main( String[] args ){ TestMenuItems theApp = new TestMenuItems(); theApp.setSize( new Dimension(200, 200)); theApp.setLocation(200, 200); theApp.setVisible( true ); } }
Does anyone know the reason why this happens and how to make the JMenuItems that are wrapped by the JPanel receive the focus of the mouse. Any idea's?
Just as a reminder, this is a small demonstration of a larger issue I have. I am not interested in how I can perform the same GUI representation using different techniques. Please only respond if you understand what is happening with my example and how to pass the events to the correct components.
Thanks
- 12-13-2010, 06:35 PM #2
Member
- Join Date
- Oct 2010
- Posts
- 63
- Rep Power
- 0
Interesting. I have never seen a JPanel placed in menu. Maybe the inner panel is eating the mouse-over evnets instead of passing them on to the menu. Just a guess.
- 12-14-2010, 09:24 AM #3
Member
- Join Date
- Dec 2010
- Posts
- 7
- Rep Power
- 0
This was my initial thought but when I placed listeners on both the inner panel and the JMenuItems non of them get triggered meaning that they never get the focus and never get the events. It's as if the Popup thinks that the focus has moved outside of it's boundry and therefore it closes itself.Maybe the inner panel is eating the mouse-over evnets instead of passing them on to the menu
Does anyone else have any other idea's?
Thanks
- 12-14-2010, 04:10 PM #4
Member
- Join Date
- Oct 2010
- Posts
- 63
- Rep Power
- 0
Is there some requirement to have item 1 to the right of item 2?
If you just want to separate them you can place a separator between 2 and 3.
Or you can cascade 1 and 2 on a sub-menu. These are customary styles for menus.
If you need need a grid of menu buttons you should probably change the popup to a
dialog intead of a JPopupMenu. Let us know your goal and we might be able to help
more.
- 12-14-2010, 05:07 PM #5
Member
- Join Date
- Dec 2010
- Posts
- 7
- Rep Power
- 0
Hi hosscomp,
Thanks again for your reply however as I previously stated, my app is:
Your last statement was:... a small demonstration of a larger issue I have. I am not interested in how I can perform the same GUI representation using different techniques
My goal is again as I have stated previously. I would like to understand why wrapping JMenuItems within a panel alters the behaviour of being able to select the Menu Items and further causes this popup menu to close? How can I update the event handling such that using a JPanel in this position still allows the popup to functions as it would usually?Let us know your goal and we might be able to help
more.
Thanks again
- 12-14-2010, 07:01 PM #6
Member
- Join Date
- Oct 2010
- Posts
- 63
- Rep Power
- 0
Sorry. I never expect things to work in an unintended way, and only 95% of the time in the specified manner.I am working on a requirement and have come across something unexpected.
Best of luck,
hosscomp
- 12-15-2010, 12:29 PM #7
Member
- Join Date
- Dec 2010
- Posts
- 7
- Rep Power
- 0
When you try and construct more than basic application you often come up again unforeseen issues. Swing components are intended to be used both as advertised and extended to include new functionality.
Even though you did not know the answer hosscomp, thanks for trying.
Does anyone else have any suggestions.
Thanks
- 12-15-2010, 03:42 PM #8
Member
- Join Date
- Oct 2010
- Posts
- 63
- Rep Power
- 0
The pleasure was all mine.
- 01-04-2011, 09:57 AM #9
Member
- Join Date
- Jan 2011
- Posts
- 1
- Rep Power
- 0
I have solved that issue, I don't know why this is happening but doing below i have resolved.
Changed the JMenuItem to JLabel, then add these to JPanel.
Need to handle mousePressed and mouseMoved method for these JLabel.
Happy Coding ... :)
- 05-06-2011, 09:53 AM #10
Member
- Join Date
- Dec 2010
- Posts
- 7
- Rep Power
- 0
Hi verma018,
Thanks for your reply, this indeed solves the issue but I have investigated further and worked out and solved the issue using the original JMenuItems also - the solution was to use a customer UI on the JMenuItem objects themselves to return the correct path to the selected menu item (the original underline problem being that this path was not being returned correctly).
Please see solution below which demonstrates both problem and solutions within a single app:
Running the application initially demonstrates the issue of the JMenuItems disappearing. Turning on the "Use Custom MenuItemUI" option demonstrates the solution. Further turning on the "Use Wrapped JLabels" demonstrates the principle solution suggested by verma018.Java Code:import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.BoxLayout; import javax.swing.ButtonGroup; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JRadioButton; import javax.swing.MenuElement; import javax.swing.MenuSelectionManager; import javax.swing.border.EtchedBorder; import javax.swing.plaf.basic.BasicMenuItemUI; public class TestMenuItems extends JFrame { private JPopupMenu _thePopup = new JPopupMenu(){ public void setVisible( boolean isVisible ){ super.setVisible( isVisible ); } }; private JRadioButton _menuItemButton = new JRadioButton("Use Wrapped JMenuItems"); //$NON-NLS-1$ private JRadioButton _labelButton = new JRadioButton("Use Wrapped JLabels"); //$NON-NLS-1$ private JRadioButton _standardButton = new JRadioButton("Use Standard JMenuItems"); //$NON-NLS-1$ private JCheckBox _useMenuItemIU = new JCheckBox("Use Custom MenuItemUI"); //$NON-NLS-1$ private JMenu _MainMenu = new JMenu("Menu"); //$NON-NLS-1$ public TestMenuItems() { this.setLayout( new BorderLayout() ); JPanel thePanel = new JPanel(); this.add( thePanel, BorderLayout.CENTER ); this.setDefaultCloseOperation( DISPOSE_ON_CLOSE ); this.addMouseListener( new MouseAdapter(){ public void mousePressed(MouseEvent e) { _thePopup.show((Component)e.getSource(), e.getX(), e.getY()); } }); _thePopup.add( _MainMenu ); thePanel.setLayout( new BorderLayout() ); addMainMenu(); // default implementation _menuItemButton.setSelected( true ); onRadioButtonPress(); } private void addMainMenu(){ JMenu theMenu = new JMenu("Main Menu"){ //$NON-NLS-1$ public void setVisible( boolean isVisible ){ super.setVisible( isVisible ); } }; ActionListener theActionListener = new ActionListener(){ public void actionPerformed( ActionEvent evt ){ onRadioButtonPress(); } }; _menuItemButton.addActionListener( theActionListener ); _labelButton.addActionListener( theActionListener ); _standardButton.addActionListener( theActionListener ); _useMenuItemIU.addActionListener( theActionListener ); ButtonGroup theGroup = new ButtonGroup(); theGroup.add( _menuItemButton ); theGroup.add( _labelButton ); theGroup.add( _standardButton ); theMenu.add( _menuItemButton ); theMenu.add( _labelButton ); theMenu.add( _standardButton ); theMenu.addSeparator(); theMenu.add( _useMenuItemIU ); JMenuBar theMenuBar = new JMenuBar(); theMenuBar.add( theMenu ); this.add( theMenuBar, BorderLayout.NORTH ); } private void onRadioButtonPress(){ _MainMenu.removeAll(); if ( _menuItemButton.isSelected() ){ // Using Menu Item addMenuItems( _MainMenu ); }else if ( _labelButton.isSelected() ){ // Using Custom JLabels addMenuLabels( _MainMenu ); }else{ // build original addStandardItems( _MainMenu ); } } private void addMenuItems( JMenu menu ){ MyJPanel theInnerPanel = new MyJPanel(); theInnerPanel.setLayout( new BoxLayout( theInnerPanel, BoxLayout.X_AXIS ) ); MyJMenuItem menuOne = new MyJMenuItem("Press 1"); //$NON-NLS-1$ MyJMenuItem menuTwo = new MyJMenuItem("Press 2"); //$NON-NLS-1$ MyJMenuItem menuThree = new MyJMenuItem("Press 3"); //$NON-NLS-1$ MyJMenuItem menuFour = new MyJMenuItem("Press 4"); //$NON-NLS-1$ if ( _useMenuItemIU.isSelected() ){ menuOne.setUI( new MyMenuItemUI() ); menuTwo.setUI( new MyMenuItemUI() ); menuThree.setUI( new MyMenuItemUI() ); menuFour.setUI( new MyMenuItemUI() ); } theInnerPanel.add( menuOne ); theInnerPanel.add( menuTwo ); menu.add(theInnerPanel); menu.add(menuThree); menu.add(menuFour); } private void addMenuLabels( JMenu menu ){ MyJPanel theInnerPanel = new MyJPanel(); theInnerPanel.setLayout( new BoxLayout( theInnerPanel, BoxLayout.X_AXIS ) ); theInnerPanel.add( new MyJLabel("Press 1") ); //$NON-NLS-1$ theInnerPanel.add( new MyJLabel("Press 2") ); //$NON-NLS-1$ menu.add(theInnerPanel); menu.add(new MyJLabel("Press 3")); //$NON-NLS-1$ menu.add(new MyJLabel("Press 4")); //$NON-NLS-1$ } private void addStandardItems( JMenu menu ){ JMenuItem menuOne = new JMenuItem("Press 1"); //$NON-NLS-1$ JMenuItem menuTwo = new JMenuItem("Press 2"); //$NON-NLS-1$ JMenuItem menuThree = new JMenuItem("Press 3"); //$NON-NLS-1$ JMenuItem menuFour = new JMenuItem("Press 4"); //$NON-NLS-1$ if ( _useMenuItemIU.isSelected() ){ menuOne.setUI( new MyMenuItemUI() ); menuTwo.setUI( new MyMenuItemUI() ); menuThree.setUI( new MyMenuItemUI() ); menuFour.setUI( new MyMenuItemUI() ); } menu.add(menuOne); menu.add(menuTwo); menu.add(menuThree); menu.add(menuFour); } public static void main( String[] args ){ TestMenuItems theApp = new TestMenuItems(); theApp.setSize( new Dimension(300, 300)); theApp.setLocation(300, 300); theApp.setVisible( true ); } class MyJMenuItem extends JMenuItem { public MyJMenuItem( String text ){ super(text); addCustomisation( this ); } } class MyJLabel extends JLabel { public MyJLabel( String text ){ super(text); addCustomisation( this ); } } public class MyJPanel extends JPanel implements MenuElement { public void processMouseEvent(MouseEvent event, MenuElement[] path, MenuSelectionManager manager) { //TODO need to implement this method, possible delegate to the contained JMenuItem(s) } public void processKeyEvent(KeyEvent event, MenuElement[] path, MenuSelectionManager manager) { //TODO need to implement this method, possible delegate to the contained JMenuItem(s) } public void menuSelectionChanged(boolean isIncluded) { //TODO need to implement this method, possible delegate to the contained JMenuItem(s) } public MenuElement[] getSubElements() { return this.getSubElements(); } public Component getComponent() { return this; } } public class MyMenuItemUI extends BasicMenuItemUI { public MenuElement[] getPath() { MenuSelectionManager m = MenuSelectionManager.defaultManager(); MenuElement oldPath[] = m.getSelectedPath(); MenuElement newPath[]; int i = oldPath.length; if (i == 0) return new MenuElement[0]; Component parent = menuItem.getParent(); if ( parent instanceof MyJPanel ) { // To deal with JXLayer/JPanel wrapping MenuElement tempPath[]; tempPath = new MenuElement[i+1]; System.arraycopy(oldPath, 0, tempPath, 0, i); tempPath[i++] = (MyJPanel)parent; oldPath = tempPath; } if (oldPath[i-1].getComponent() == parent) { // The parent popup menu is the last so far newPath = new MenuElement[i+1]; System.arraycopy(oldPath, 0, newPath, 0, i); newPath[i] = menuItem; } else { // A sibling menuitem is the current selection // // This probably needs to handle 'exit submenu into // a menu item. Search backwards along the current // selection until you find the parent popup menu, // then copy up to that and add yourself... int j; for (j = oldPath.length-1; j >= 0; j--) { if (oldPath[j].getComponent() == parent) break; } newPath = new MenuElement[j+2]; System.arraycopy(oldPath, 0, newPath, 0, j+1); newPath[j+1] = menuItem; /* System.out.println("Sibling condition -- "); System.out.println("Old array : "); printMenuElementArray(oldPath, false); System.out.println("New array : "); printMenuElementArray(newPath, false); */ } return newPath; } } private void addCustomisation( final JComponent comp ){ final Color defaultBackgroundColor = this.getBackground(); final Color defaultForegroundColor = this.getForeground(); comp.setBorder( new EtchedBorder() ); comp.addMouseListener( new MouseAdapter(){ public void mouseClicked(MouseEvent e) { comp.setBackground( defaultBackgroundColor ); comp.setForeground( defaultForegroundColor ); onMouseClickEvent(e); } public void mousePressed(MouseEvent e) { comp.setBackground( defaultBackgroundColor ); comp.setForeground( defaultForegroundColor ); onMouseClickEvent(e); } public void mouseReleased(MouseEvent e) { comp.setBackground( defaultBackgroundColor ); comp.setForeground( defaultForegroundColor ); onMouseClickEvent(e); } public void mouseEntered(MouseEvent e) { comp.setBackground( Color.RED ); comp.setForeground( Color.BLUE ); } public void mouseExited(MouseEvent e) { comp.setBackground( defaultBackgroundColor ); comp.setForeground( defaultForegroundColor ); } }); } private void onMouseClickEvent( MouseEvent evt ){ String strComponentText = ""; //$NON-NLS-1$ if ( evt.getSource() instanceof JLabel ) strComponentText = "JLabel MouseClicked: " +((JLabel)evt.getSource()).getText(); //$NON-NLS-1$ if ( evt.getSource() instanceof JMenuItem ) strComponentText = "JMenuItem MouseClicked: " +((JMenuItem)evt.getSource()).getText(); //$NON-NLS-1$ System.out.println( strComponentText ); if ( evt.getSource() instanceof JLabel ){ _thePopup.setVisible( false ); } } }
Thanks again for all your help guys.Last edited by snoopygee; 05-06-2011 at 09:58 AM.
Similar Threads
-
adding a buffered image over a jpanel
By fatmat9 in forum New To JavaReplies: 1Last Post: 11-23-2010, 03:23 AM -
How to display info when a JPanel gains focus
By toymachiner62 in forum Java AppletsReplies: 8Last Post: 10-19-2009, 05:13 AM -
adding a jpanel in the middle of the script
By 2o2 in forum AWT / SwingReplies: 11Last Post: 10-12-2008, 05:50 PM -
Selecting a JMenu paints over the JPanel on the content pane
By Swingset in forum AWT / SwingReplies: 3Last Post: 01-05-2008, 11:13 PM


LinkBack URL
About LinkBacks
Reply With Quote
Bookmarks