KeyStroke Accelerator not working after disabling JMenuItem - java

Within a small Java standalone program with a Swing GUI I use JMenuItem with Accelerator - mostly without any problems:
JMenuItem item = new JMenuItem("Connect", 'C');
KeyStroke ks = KeyStroke.getKeyStroke('C', Event.CTRL_MASK);
item.setAccelerator(ks);
item.addActionListener(this);
My problem is that when I disable the item with
item.setEnabled(false);
and enable it later with
item.setEnabled(true);
I cannot use the accelerator any more. The JMenuItem is correctly shown as enabled in the menu and I can click it with the mouse (and my ActionListener is correctly working) but my accelerator isn't working - so I cannot start "Connect" with Ctrl+C any more.
Does anyone of you know what this problem is or how I can avoid it?
Other menu items which accelerators (but without beeing temporarily disabled) are working. When calling
item.getAccelerator();
after calling item.setEnabled(true) I get the formerly set KeyStroke.
It works with the KeyStroke Ctrl+U but not with Ctrl+C. It seems to me that when disabling the menu item the default copy operation is registered again with Ctrl+C and after enabling the menu item again there's no connection between the KeyStroke and the menu item any more.
While trying to build a small copy of my program to demonstrate the problem I got it:
I did two things together - enabled the JMenuItem (with KeyStroke Ctrl+C) AND requested focus for a JTextField.
Here's a small code for a program that does not react on the KeyStroke Ctrl+C, which is connected to a menu item:
public class ProblemDemo extends JFrame implements ActionListener {
public ProblemDemo() {
super("ProblemDemo");
setSize(500,500);
setLocation(500,300);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JMenuBar menubar = new JMenuBar();
JMenuItem menuItem = new JMenuItem("JMenuItem", 'C');
menuItem.setAccelerator(KeyStroke.getKeyStroke('C', Event.CTRL_MASK));
menuItem.addActionListener(this);
JMenu menu = new JMenu("Actions");
menu.add(menuItem);
menubar.add(menu);
setJMenuBar(menubar);
JTextArea textarea = new JTextArea();
getContentPane().setLayout(new BorderLayout());
getContentPane().add(textarea, BorderLayout.CENTER);
setVisible(true);
}
#Override
public void actionPerformed(ActionEvent event) {
if ("JMenuItem".equals(event.getActionCommand())) {
System.out.println("JMenuItem clicked");
}
}
public static void main(String[] args) {
new ProblemDemo();
}
}

I had the same problem trying to enable the copy/cut menu items (as well as buttons in a toolbar), only if something is selected in a JTable by calling setEnabled (true) in a ListSelectionListener.
I solve my problem by calling requestFocusInWindow for the JMenuBar containing the items each time setEnable (true) is called.
Seems that selecting something in the table directs Ctrl+C / Ctrl+x to the table...
May be it'll help

Try to create the following method:
private KeyStroke getNewKeyStroke(){
KeyStroke ks = KeyStroke.getKeyStroke('C', Event.CTRL_MASK);
return KeyStroke;
}
then you can call the following method like that:
item.setEnabled(true);
item.setAccelerator(this.getNewKeyStroke());

Related

Add accelerator description to JMenuItem in GUI, without actually adding an accelerator

I'm trying to set some text to be displayed where the accelerator binding is usually displayed, for a JMenuItem.
The demarcated Ctrl+Z text in the following image is an example of what I'm trying to set, for another JMenuItem.
I don't actually want to set an accelerator for this JMenuItem, though.
I've poked around the source for several classes, like JMenuItem and BasicMenuItemUI, to no avail.
What's the simplest way to achieve this?
Thanks in advance :)
I assume the reason you want this is so you can prevent the menu from triggering the undo action a second time, when the key combination is already bound on a component on the frame, but this shouldn't be necessary. If the component consumes the key event, the menu won't detect it.
Here's an example with a JTextArea to see what I mean:
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JMenuBar menu = new JMenuBar();
frame.setJMenuBar(menu);
JMenu menuEdit = new JMenu("Edit");
menu.add(menuEdit);
JMenuItem menuEditUndo = new JMenuItem("Undo");
menuEdit.add(menuEditUndo);
menuEditUndo.setAccelerator(KeyStroke.getKeyStroke("control Z"));
menuEditUndo.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("menu");
}
});
JTextArea textArea = new JTextArea(20, 40);
textArea.getInputMap().put(KeyStroke.getKeyStroke("control Z"), "undo");
textArea.getActionMap().put("undo", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("text");
}
});
frame.add(new JScrollPane(textArea));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Both the text area and the menu item have bound to the same key combo, but pressing Ctrl+Z while the text area has focus prints only "text" and never "menu". I.e., the action does not happen twice. Although this uses a JTextArea, it should be true of any component.

Where do you store the logic for a JPopupMenu?

I'm a little confused on where the action logic (what happens when a user selects a menu item from the popup) should be placed. Currently, I have it stored in a subclass of JPopupMenu, but it doesn't seem to call the event when I click on a menu item.
Subclass code:
public class MyPopupMenu extends JPopupMenu {
JMenuItem item1;
JMenuItem item2;
public MyPopupMenu() {
item1 = new JMenuItem("New Tab");
item2 = new JMenuItem("Close Tab");
add(item1);
add(item2);
}
class myListener extends MouseAdapter {
#Override
public void mouseClicked(MouseEvent ev) {
System.out.println("I've been clicked!");
}
}
}
I attached this to my JTabbedPane by calling the setComponentPopupMenumethod.
myTabPane.setComponentPopupMenu(myPopupMenu);
This compiles OK. And it does show the popup menu as expected, but upon selecting one of the menu options in the popup, all is silent. No message gets displayed. Do I need to put it somewhere else?
you have to add MouseListener to JMenuItems
add proper listener to use Swing Action, ActionListener for JMenuItems, read Oracle tutorial for working code example
Add MouseListner to your menu item
myListener myListener = new myListener();
item1.addMouseListener(myListener);
item2.addMouseListener(myListener);
Seems your approach is bit wrong. Please refer How to Use Menus

JMenu consumes focuslost event in Windows7 LAF Java7

If a popup menu is still open when another component is clicked, then the component does not get the event, because it's probably consumed by the popup. This happens for all JPopupmenus in general.
This happens only in Java 7 with windows LAF (Windows7). Is there a workaround? Is it a known bug?
import javax.swing.*;
import java.awt.event.*;
public class Test
{
public static void main(String[] s)
throws Exception
{
String lookAnfFeelClassName = UIManager.getSystemLookAndFeelClassName();
UIManager.setLookAndFeel(lookAnfFeelClassName);
JMenu menu = new JMenu("TEST Menu");
JMenuItem menuItem = new JMenuItem("Menu Item 1");
JMenuBar menuBar = new JMenuBar();
menu.add(menuItem);
menuBar.add(menu);
final JButton b = new JButton("Test");
b.setBounds(5, 50, 60, 20);
b.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//If the Menu is open when I press the button, the putton is not pressed
//so I have to press it again.
JOptionPane.showMessageDialog(b, "Button Pressed");
}
}
);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(150, 150);
frame.setJMenuBar(menuBar);
frame.getContentPane().setLayout(null);
frame.getContentPane().add(b);
frame.setVisible(true);
}
}
Here is the magic line that fixes the problem:
UIManager.put("PopupMenu.consumeEventOnClose", Boolean.FALSE);
I found this after looking into the source code for the BasicPopupMenuUI class. Apparently this behaviour is a deliberate design choice according to the following comments in the code, but it sure feels like a bug to me.
// Ask UIManager about should we consume event that closes
// popup. This made to match native apps behaviour.
By the way, it happens in Java 5 and 6 too.

How to display a menu and a panel in the same window in Java Swing?

I've got a JMenu and I want to change the window's content according to what button from the menu is pressed. I managed to show the panel as a popup, but I want it to be displayed in the same window with the menu. This is my code so far :
public class GUImenu extends JFrame
{
private JMenuBar menuBar;
private JMenu menu;
private JMenu subMenu;
private JMenuItem item1;
private JMenuItem item2;
private JMenuItem item3;
private JMenuItem item4;
private JMenuItem item5;
private JMenuItem item6;
public GUImenu()
{
super("Example Menu System");// Call the JFrame constructor.
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Specify an action for the close button.
buildMenuBar();
// Pack and display the window.
pack();
setSize(1000, 250); // set frame size
setVisible(true);
}
private void buildMenuBar()
{
// Create the menu bar.
menuBar = new JMenuBar();
// Create the file and text menus.
menu = new JMenu("Menu"); menuBar.add(menu);
subMenu = new JMenu("Create Customer");
item1 = new JMenuItem("Ordinary Customer"); subMenu.add(item1);
item1.addActionListener(new showOrdinaryCust());
item6 = new JMenuItem("Privileged Customer"); subMenu.add(item6);
menu.add(subMenu);
item2 = new JMenuItem("View Customers Who Didn't Pay"); menu.add(item2);
item3 = new JMenuItem("Remove Client");menu.add(item3);
item4 = new JMenuItem("Create Order"); menu.add(item4);
item5 = new JMenuItem("Search..."); menu.add(item5);
setJMenuBar(menuBar);
}
public static void main(String[] args)
{
new GUImenu();
}
private class showOrdinaryCust implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
if(event.getSource()==item1)
GUIpanel.main(null);
}
}
}
I would try to fill the entire window with a CardLayout. CardLayout is meant to switch its contents between separate views. Simply set up multiple cards for each of the panels you want to show and have the menu switch between them.
If you use windows or dialogs you will latter have to deal with the focus, the closing, minimizing, maximizing, re-size, centering, visibility...
In your case i would recommend you to pick a good layout to suit your needs(Probably the easiest way to achieve your goal).
What do you think about tabbed panes?
See this link: http://docs.oracle.com/javase/tutorial/uiswing/components/tabbedpane.html
building guis is a little complex, but worth the time spent to understand what options are. This is a good place to start as it explains various java gui layouts, including using a layout manager. http://docs.oracle.com/javase/tutorial/uiswing/layout/using.html.
For future posts, your example should be complete, including imports so we can copy and paste code, compile and look at.
It is simple enough. I have implemented this thing as follows :
First get content pane of your JFrame, say in container. Make this container object static.
private static Container container;
now get content pane.
container = this.getContentPane();
Now on click on menu call some method that will do some thing like this :
container.removeAll();
container.add(new JPanel()); //Add object of your panel you want to show.
container.revalidate();
This method is helpful in case you want to show multiple panels in same JFrame.

JMenu setDelay() pop down delay

In my application, I have a JPopupMenu that displays a set of sub-menus:
private static JMenu createMenu(String title) {
JMenu menu = new JMenu(title);
menu.setDelay(2000);
menu.add(new JMenuItem("123"));
menu.add(new JMenuItem("234"));
menu.add(new JMenuItem("345"));
return menu;
}
public static void main(String[] args) {
JFrame frame = new JFrame("Hello");
final JButton button = new JButton("Test");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JPopupMenu jpm = new JPopupMenu();
jpm.add(createMenu("XXX"));
jpm.add(createMenu("YYY"));
jpm.add(createMenu("ZZZ"));
jpm.show(button, 0, 0);
}
});
frame.add(button);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
}
This application usually runs on Windows.
I first mouse-over the first XXX sub-menu. Sometimes, I accidentally move my mouse over YYY, which then causes the first sub-menu to disappear immediately.
From reading the Javadoc, it would seem that calling JMenu.setDelay(2000) should suggest that the JMenu's popup menu wait 2 seconds before popping down. However, it only seems to delay the next menu 2 seconds before popping up.
Is there a way to delay the pop down?
Update
Here's something interesting; from Bug #6563939 Delay should be respected before hiding a JMenu, open since 2007
Javadoc might be misleading in this
point. It says "before submenus are
popped up or down". "Popping down"
could be understood as "hiding", but
it rather has the meaning of "submenu
is rendered below his parent menu".
It also seems to suggest that this depends on the L&F you're using, so it looks like more like something you can only request or hint at:
Each look and feel (L&F) may determine
it's own policy for observing the
delay property. In most cases, the
delay is not observed for top level
menus or while dragging. This method
is a property of the look and feel
code and is used to manage the
idiosyncracies of the various UI
implementations.

Categories

Resources