I am a beginner using GWT. I have a menubar which I want to retain on the screen even if the mouse is not over it. However when the mouse is not over the menubar and clicked somewhere on the screen then I want the menubar to disappear. I tried using the MouseOutEvent but I need it to fire only when the mouse is clicked not just out. Any help would be appreciated.
this.menu.addDomHandler(menuHoverOutHandler, MouseOutEvent.getType());
MouseOutHandler menuHoverOutHandler = new MouseOutHandler() {
public void onMouseOut(MouseOutEvent event) {
Window.alert("I am outside the region");
}
};
Below is a fully working answer taken from my live app:
The way I solved the menu close on mouse out was to run a boolean variable "isMouseOut" in the top of the constructor to keep track, and then allocate the MouseListener in a more OO friendly way to keep track of the multiple MouseIn-MouseOut events as a user interacts with the menu. Which calls a separate menuClear method acting upon the state of the boolean "isMouseOut". The class implements MouseListener. This is how its done.
Create an ArrayList adding all the menu items to this array first. Like so:
Font menuFont = new Font("Arial", Font.PLAIN, 12);
JMenuBar menuBar = new JMenuBar();
getContentPane().add(menuBar, BorderLayout.NORTH);
// Array of MenuItems
ArrayList<JMenuItem> aMenuItms = new ArrayList<JMenuItem>();
JMenuItem mntmRefresh = new JMenuItem("Refresh");
JMenuItem mntmNew = new JMenuItem("New");
JMenuItem mntmNormal = new JMenuItem("Normal");
JMenuItem mntmMax = new JMenuItem("Max");
JMenuItem mntmStatus = new JMenuItem("Status");
JMenuItem mntmFeedback = new JMenuItem("Send Feedback");
JMenuItem mntmEtsyTWebsite = new JMenuItem("EtsyT website");
JMenuItem mntmAbout = new JMenuItem("About");
aMenuItms.add(mntmRefresh);
aMenuItms.add(mntmNew);
aMenuItms.add(mntmNormal);
aMenuItms.add(mntmMax);
aMenuItms.add(mntmStatus);
aMenuItms.add(mntmFeedback);
aMenuItms.add(mntmEtsyTWebsite);
aMenuItms.add(mntmAbout);
then iterate over the arrayList at this stage adding a MouseListener using the for() loop:
for (Component c : aMenuItms) {
if (c instanceof JMenuItem) {
c.addMouseListener(ml);
}
}
Now set JMenu parents for the MenuBar:
// Now set JMenu parents on MenuBar
final JMenu mnFile = new JMenu("File");
menuBar.add(mnFile).setFont(menuFont);
final JMenu mnView = new JMenu("View");
menuBar.add(mnView).setFont(menuFont);
final JMenu mnHelp = new JMenu("Help");
menuBar.add(mnHelp).setFont(menuFont);
Then add the dropdown menuItems children to the JMenu parents:
// Now set menuItems as children of JMenu parents
mnFile.add(mntmRefresh).setFont(menuFont);
mnFile.add(mntmNew).setFont(menuFont);
mnView.add(mntmNormal).setFont(menuFont);
mnView.add(mntmMax).setFont(menuFont);
mnHelp.add(mntmStatus).setFont(menuFont);
mnHelp.add(mntmFeedback).setFont(menuFont);
mnHelp.add(mntmEtsyTWebsite).setFont(menuFont);
mnHelp.add(mntmAbout).setFont(menuFont);
Add the mouseListeners to the JMenu parents as a separate step:
for (Component c : menuBar.getComponents()) {
if (c instanceof JMenu) {
c.addMouseListener(ml);
}
}
Now that the child menuItem elements all have their own listeners that are separate to the parent JMenu elements and the MenuBar itself - It is important to identify the object type within the MouseListener() instantiation so that you get the menu auto opening on mouseover (in this example the 3x JMenu parents) BUT ALSO avoids child exception errors and allows clean identification of mouseOUT of the menu structure without trying to monitor where the mouse position is. The MouseListener is as follows:
MouseListener ml = new MouseListener() {
public void mouseClicked(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
isMouseOut = true;
timerMenuClear();
}
public void mouseEntered(MouseEvent e) {
isMouseOut = false;
Object eSource = e.getSource();
if(eSource == mnHelp || eSource == mnView || eSource == mnFile){
((JMenu) eSource).doClick();
}
}
};
The above only simulates the mouse click into the JMenu 'parents' (3x in this example) as they are the triggers for the child menu dropdowns. The timerMenuClear() method calls on the MenuSelectionManager to empty whatever selectedpath point was live at the time of real mouseOUT:
public void timerMenuClear(){
ActionListener task = new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(isMouseOut == true){
System.out.println("Timer");
MenuSelectionManager.defaultManager().clearSelectedPath();
}
}
};
//Delay timer half a second to ensure real mouseOUT
Timer timer = new Timer(1000, task);
timer.setInitialDelay(500);
timer.setRepeats(false);
timer.start();
}
It took me a little testing, monitoring what values I could access within the JVM during its development - but it Works a treat! even with nested menus :) I hope many find this full example very useful.
Use widget's blur handler. It detects when the widget lost focus.
Related
I know how to create Java Swing submenus using JMenu. When we hover the mouse over a JMenu object, it displays a JPopupMenu showing the submenu items, like this:
Submenu using JMenu
My problem is that in my application, determining which menu elements will have a submenu is expensive. I don't want to have to determine in advance whether a particular menu element should be a JMenu or just a JMenuItem. I want to make every element a JMenuItem and display a submenu for it only if the user requests it by, e.g., hovering the mouse over a menu item. Like this:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Menu2 extends JFrame
{
public Menu2()
{
super("Menu2");
JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);
JMenu mItems = new JMenu("Items");
menuBar.add(mItems);
mItems.add(new JMI("A"));
mItems.add(new JMI("B"));
mItems.add(new JMI("C"));
JLabel stuff = new JLabel("Other stuff");
stuff.setPreferredSize(new Dimension(200,200));
getContentPane().add(stuff);
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
private class JMI extends JMenuItem
implements MouseListener
{
public JPopupMenu childrenPopup = null;
public JMI(String label)
{
super(label);
addMouseListener(this);
}
// MouseListener
public void mouseClicked(MouseEvent ev) {}
public void mouseEntered(MouseEvent ev)
{
// Show a submenu for item "B" only.
// In real life we'd want a Timer to delay showing the submenu
// until we are sure the user is hovering the mouse.
// For simplicity I've omitted it.
if (getText().equals("B")) {
if (childrenPopup == null) {
childrenPopup = new JPopupMenu();
// Expensive processing to determine submenu elements...
childrenPopup.add("D");
childrenPopup.add("E");
}
// Display the submenu
childrenPopup.show(this,getWidth(),0);
}
}
public void mouseExited(MouseEvent ev) {}
public void mousePressed(MouseEvent ev) {}
public void mouseReleased(MouseEvent ev) {}
}
public static void main(String[] args)
throws Exception
{
new Menu2().setVisible(true);
}
}
The only problem is that when my manually created JPopupMenu is displayed, the rest of the menu gets closed. The resulting display does not look like the earlier one, but rather like this:
Submenu displayed manually
Note that I did not click on the "B" menu item, only moved the mouse into it. The menu did not close due to a mouse click.
How can I do what JMenu does -- display a JPopupMenu without closing the rest of the menu?
The approach I've tentatively decided upon is to extend JMenu instead
of JMenuItem and use this type for all of my menu elements. But I
won't populate these elements (the expensive step) until the user
requests it by hovering the mouse.
To avoid cluttering up the menu with the arrow icons that JMenu
normally displays (potentially misleading in this case), I use a technique described by Stackoverflow's MadProgrammer to instantiate an arrowless JMenu in a static factory method. Since I
restore the arrow icon property after creating the arrowless JMenu,
normal JMenu instances created elsewhere will still show the arrow.
Some menu elements will need to execute actions and close the menu,
like a JMenuItem does. A JMenu doesn't normally respond to mouse
clicks, so I execute click actions in my MouseListener.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class Menu3 extends JFrame
{
public Menu3()
{
super("Menu3");
JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);
JMenu mItems = new JMenu("Items");
menuBar.add(mItems);
mItems.add(JM.create("A"));
mItems.add(JM.create("B"));
mItems.add(JM.create("C"));
JLabel stuff = new JLabel("Other stuff");
stuff.setPreferredSize(new Dimension(200,200));
getContentPane().add(stuff);
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
private static class JM extends JMenu
implements MouseListener
{
private static final String ARROW_ICON_KEY = "Menu.arrowIcon";
private boolean populated = false; // Submenu already populated?
protected JM(String label)
{
super(label);
addMouseListener(this);
}
// This static factory method returns a JM without an arrow icon.
public static JM create(String label)
{
UIDefaults uiDefaults = UIManager.getLookAndFeelDefaults();
Object savedArrowIcon = uiDefaults.get(ARROW_ICON_KEY);
uiDefaults.put(ARROW_ICON_KEY,null);
JM newJM = new JM(label);
uiDefaults.put(ARROW_ICON_KEY,savedArrowIcon);
return newJM;
}
// MouseListener
public void mouseClicked(MouseEvent ev)
{
// Since some menu elements need to execute actions and a JMenu
// doesn't normally respond to mouse clicks, we execute click
// actions here. In real life we'll probably fire some event
// for which an EventListener can listen. For illustrative
// purposes we'll just write out a trace message.
System.err.println("Executing "+getText());
MenuSelectionManager.defaultManager().clearSelectedPath();
}
public void mouseEntered(MouseEvent ev)
{
// In real life we'd want a Timer to delay showing the submenu
// until we are sure the user is "hovering" the mouse.
// For simplicity I've omitted it.
// Populate this submenu only once
if (!populated) {
// For purposes of example, show a submenu for item "B" only.
if (getText().equals("B")) {
// Expensive processing...
add(create("D"));
add(create("E"));
}
populated = true;
}
}
public void mouseExited(MouseEvent ev) {}
public void mousePressed(MouseEvent ev) {}
public void mouseReleased(MouseEvent ev) {}
}
public static void main(String[] args)
throws Exception
{
new Menu3().setVisible(true);
}
}
The result works the way I want:
Menu3 with open menu
Example code:
public class FrameMenuTextFieldTest {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
final JFrame frame = new JFrame();
frame.getContentPane().add(new JTextField());
JMenuBar menubar = new JMenuBar();
JMenu menu = new JMenu("Menu");
JMenuItem item = new JMenuItem("Item1");
item.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(frame, "Menu Item clicked");
}
});
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_5, 0));
menu.add(item);
menubar.add(menu);
frame.setJMenuBar(menubar);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
});
}
}
The problem here is if I type 5 into the textfield, not only the textfield gets this event, but the menu item as well, and its action is performed; message shown.
What is the simplest way to disable the key event propagation to the menu bar?
I my real application, I have a lot of menu items to disable for a few textfields.
Bind the JMenuItem with some modifiers such as Ctrl, Alt, Shift etc. if possible as mentioned here KeyStroke#getKeyStroke().
Try something like as shown below to bind it with Ctrl+5.
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_5, InputEvent.CTRL_DOWN_MASK));
EDIT
It might help you if you don't want to use any modifier.
If the current focusable component is not JTextField then perform action on JMenuItem.
Sample code:
JMenuItem item = new JMenuItem("Item1");
item.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Component component = frame.getFocusOwner();
if (!(component instanceof JTextField)) {
JOptionPane.showMessageDialog(frame, "Menu Item clicked");
}
}
});
Read more here on In Swing, how can I find out what object currently has focus?
I've got a new UI I'm working on implementing in Java and I'm having trouble implementing a JPopupMenu containing a JMenu (as well as several JMenuItems), which itself contains several JMenuItems. The JPopupMenu appears where I click the RMB, and it looks good, but the "Connect" JMenu doesn't seem to have any children when I mouse-over, despite my best efforts to .add() them.
Having looked at several examples online, I haven't seen any that specifically implement a listener for mouseEntered() to roll out the sub-items. I'm of a mind that I'm messing something up in my menu initialization method.
I've attached the pertinent code for your perusal.
//Elsewhere...
private JPopupMenu _clickMenu;
//End Elsehwere...
private void initializeMenu()
{
_clickMenu = new JPopupMenu();
_clickMenu.setVisible(false);
_clickMenu.add(generateConnectionMenu());
JMenuItem menuItem;
menuItem = new JMenuItem("Configure");
addMenuItemListeners(menuItem);
_clickMenu.add(menuItem);
menuItem = new JMenuItem("Status");
addMenuItemListeners(menuItem);
_clickMenu.add(menuItem);
}
private JMenu generateConnectionMenu()
{
JMenu menu = new JMenu("Connect");
List<Port> portList = _database.getAllPortsInCard(_cardId);
for(int i = 0; i < portList.size(); i++)
{
menu.add(new JMenuItem(portList.get(i).getName()));
}
return menu;
}
The code is certainly not the prettiest, but go easy on me as it's been altered too many times today as time permitted while I tried to figure out why this wasn't working. I'm thinking it may be a question of scope, but I've tried a few different code configurations to no avail. Feel free to ask any followup questions or smack me for an obvious oversight (it's happened before...). Thanks all!
Edit:
Chalk this one up to a lack of experience with Java and Swing... I was manually positioning and making the JPopupMenu visible instead of using the JComponent.setComponentPopupMenu(menu) method. After doing this for the card module in the above image (itself a JButton), the submenu displays correctly. A different, functional version of the initialization code is included below.
private void initializeMenu()
{
_cardMenu = new JPopupMenu();
JMenu menu = new JMenu("Connect");
JMenuItem menuItem;
menuItem = new JMenuItem("1");
menu.add(menuItem);
menuItem = new JMenuItem("2");
menu.add(menuItem);
_cardMenu.add(menu);
_cardMenu.add(new JMenuItem("Configure"));
_cardMenu.add(new JMenuItem("Status"));
_mainButton.setComponentPopupMenu(_cardMenu); //Important, apparently!
}
So, lesson learned. Thanks for the help guys!
This is common Bug or Swing property that in one moment can be visible only one Lightweight popup window, same issue is e.g. with popup from JComboBox added into JPopupMenu,
change Lightweight property to the Heavyweight
better would be
use un_decorated JDialog or JOptionPane with JComponents
EDIT #trashgod
everything works as I excepted, all JMenus, JMenuItems are visible and repeatly fired correct evets
code
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class ContextMenu implements ActionListener, MenuListener, MenuKeyListener {
private JTextArea textArea = new JTextArea();
public ContextMenu() {
final JPopupMenu contextMenu = new JPopupMenu("Edit");
JMenu menu = new JMenu("Sub Menu");
menu.add(makeMenuItem("Sub Menu Save"));
menu.add(makeMenuItem("Sub Menu Save As"));
menu.add(makeMenuItem("Sub Menu Close"));
menu.addMenuListener(this);
JMenu menu1 = new JMenu("Sub Menu");
menu1.add(makeMenuItem("Deepest Sub Menu Save"));
menu1.add(makeMenuItem("Deepest Sub Menu Save As"));
menu1.add(makeMenuItem("Deepest Sub Menu Close"));
menu.add(menu1);
menu1.addMenuListener(this);
contextMenu.add(menu);
contextMenu.add(makeMenuItem("Plain Save"));
contextMenu.add(makeMenuItem("Plain Save As"));
contextMenu.add(makeMenuItem("Plain Close"));
contextMenu.addMenuKeyListener(this);
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
frame.add(panel);
panel.setComponentPopupMenu(contextMenu);
textArea.setInheritsPopupMenu(true);
panel.add(BorderLayout.CENTER, textArea);
JTextField textField = new JTextField();
textField.setInheritsPopupMenu(true);
panel.add(BorderLayout.SOUTH, textField);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 200);
frame.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
textArea.append(e.getActionCommand() + "\n");
}
private JMenuItem makeMenuItem(String label) {
JMenuItem item = new JMenuItem(label);
item.addActionListener(this);
return item;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
ContextMenu contextMenu = new ContextMenu();
}
});
}
public void menuSelected(MenuEvent e) {
textArea.append("menuSelected" + "\n");
}
public void menuDeselected(MenuEvent e) {
textArea.append("menuDeselected" + "\n");
}
public void menuCanceled(MenuEvent e) {
textArea.append("menuCanceled" + "\n");
}
public void menuKeyTyped(MenuKeyEvent e) {
textArea.append("menuKeyTyped" + "\n");
}
public void menuKeyPressed(MenuKeyEvent e) {
textArea.append("menuKeyPressed" + "\n");
}
public void menuKeyReleased(MenuKeyEvent e) {
textArea.append("menuKeyReleased" + "\n");
}
}
I don't see an obvious problem in the code shown, although #mKorbel's point may apply. For reference, this ControlPanel adds a subMenu with several items.
I am trying to create a JMenuItem that is disabled by default, but a method can be called to enable it. Just for the moment whilst I'm testing out my code, I want the method to be called when I click on another menu item. I have had a look at the documentation for JMenuItem, but I'm pretty new to Java and I'm having trouble finding exactly what I need. I've tried using the updateUI() command, but I that hasn't worked, so I'm totally stuck. Thanks in advance for any help :)
This is what I have so far:
public class initialScreen extends JFrame implements ActionListener{
Dimension screenSize = new Dimension(800,600);
JMenuItem runE, newP;
public initialScreen(){
super("Experiment Control Suite");
setSize(screenSize);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JMenuBar bar = new JMenuBar();
JMenuItem newP = new JMenuItem("New");
newP.addActionListener(this);
runE = new JMenuItem("Run");
runE.setEnabled(false);
runE.addActionListener(this);
JMenu exp = new JMenu("Experiment");
exp.add(runE);
JMenu par = new JMenu("Participant");
par.add(newP);
bar.add(exp);
bar.add(par);
setJMenuBar(bar);
setVisible(true);
}
public void enableRun(){
runE.setEnabled(true);
runE.updateUI();
}
public void actionPerformed(java.awt.event.ActionEvent e){
if(e.getSource() == newP) {
enableRun();
}
else if(e.getSource() == runE) {
System.out.println("run has been clicked");
}
}
}
Your method enableRun is never invoked because of the following line:
JMenuItem newP = new JMenuItem("New");
Instead, refactor it as such,
newP = new JMenuItem("New");
Now, the field will be correctly initialized and registered as an ActionListener. And thus, when checking the source, enableRun will be invoked and the menu item will be enabled.
Note that in this case, updateUI is completely unnecessary (I suggest you read the javadoc to learn its purpose).
I am new to Java and I was wondering how to add functionality to menu item?
What I would like it to do, is to set two values to 0.
This is the code I have currently:
JMenuItem clear = new JMenuItem("Clear");
Options.add(clear);
This example is from the book "Java
Foundation Classes in a Nutshell".
Written by David Flanagan. Copyright
(c) 1999 by O'Reilly & Associates.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MenuDemo {
public static void main(String[] args) {
// Create a window for this demo
JFrame frame = new JFrame("Menu Demo");
JPanel panel = new JPanel();
frame.getContentPane().add(panel, "Center");
// Create an action listener for the menu items we will create
// The MenuItemActionListener class is defined below
ActionListener listener = new MenuItemActionListener(panel);
// Create some menu panes, and fill them with menu items
// The menuItem() method is important. It is defined below.
JMenu file = new JMenu("File");
file.setMnemonic('F');
file.add(menuItem("New", listener, "new", 'N', KeyEvent.VK_N));
file.add(menuItem("Open...", listener, "open", 'O', KeyEvent.VK_O));
file.add(menuItem("Save", listener, "save", 'S', KeyEvent.VK_S));
file.add(menuItem("Save As...", listener, "saveas", 'A', KeyEvent.VK_A));
JMenu edit = new JMenu("Edit");
edit.setMnemonic('E');
edit.add(menuItem("Cut", listener, "cut", 0, KeyEvent.VK_X));
edit.add(menuItem("Copy", listener, "copy", 'C', KeyEvent.VK_C));
edit.add(menuItem("Paste", listener, "paste", 0, KeyEvent.VK_V));
// Create a menubar and add these panes to it.
JMenuBar menubar = new JMenuBar();
menubar.add(file);
menubar.add(edit);
// Add menubar to the main window. Note special method to add menubars
frame.setJMenuBar(menubar);
// Now create a popup menu and add the some stuff to it
final JPopupMenu popup = new JPopupMenu();
popup.add(menuItem("Open...", listener, "open", 0, 0));
popup.addSeparator(); // Add a separator between items
JMenu colors = new JMenu("Colors"); // Create a submenu
popup.add(colors); // and add it to the popup menu
// Now fill the submenu with mutually-exclusive radio buttons
ButtonGroup colorgroup = new ButtonGroup();
colors.add(radioItem("Red", listener, "color(red)", colorgroup));
colors.add(radioItem("Green", listener, "color(green)", colorgroup));
colors.add(radioItem("Blue", listener, "color(blue)", colorgroup));
// Arrange to display the popup menu when the user clicks in the window
panel.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
// Check whether this is the right type of event to pop up a popup
// menu on this platform. Usually checks for right button down.
if (e.isPopupTrigger())
popup.show((Component)e.getSource(), e.getX(), e.getY());
}
});
// Finally, make our main window appear
frame.setSize(450, 300);
frame.setVisible(true);
}
// A convenience method for creating menu items.
public static JMenuItem menuItem(String label,
ActionListener listener, String command,
int mnemonic, int acceleratorKey) {
JMenuItem item = new JMenuItem(label);
item.addActionListener(listener);
item.setActionCommand(command);
if (mnemonic != 0) item.setMnemonic((char) mnemonic);
if (acceleratorKey != 0)
item.setAccelerator(KeyStroke.getKeyStroke(acceleratorKey,
java.awt.Event.CTRL_MASK));
return item;
}
// A convenience method for creating radio button menu items.
public static JMenuItem radioItem(String label, ActionListener listener,
String command, ButtonGroup mutExGroup) {
JMenuItem item = new JRadioButtonMenuItem(label);
item.addActionListener(listener);
item.setActionCommand(command);
mutExGroup.add(item);
return item;
}
// A event listener class used with the menu items created above.
// For this demo, it just displays a dialog box when an item is selected.
public static class MenuItemActionListener implements ActionListener {
Component parent;
public MenuItemActionListener(Component parent) { this.parent = parent; }
public void actionPerformed(ActionEvent e) {
JMenuItem item = (JMenuItem) e.getSource();
String cmd = item.getActionCommand();
JOptionPane.showMessageDialog(parent, cmd + " was selected.");
}
}
}
Hope it help you get started
You will need to add an ActionListener. This is an interface which must implement a method called actionPerformed.
E.g
clear.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent actionEvent) {
// Clear two values.
}
});`
This will add an anonymous ActionListener that is invoked once the JMenuItem is clicked.
Hope that helps.