Java JMenu setAccelerator() problem - java

When I set setAccelerator() to Control + A or Control + P and I run the program it doesn't detect the keystroke.
Here's the code:
menuItem = new JMenuItem("About");
menuItem.setActionCommand("About");
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, Event.CTRL_MASK));
menuItem.setMnemonic(KeyEvent.VK_A);
menuItem.addActionListener(this);
menu.add(menuItem);
Then when it's pressed it should invoke the Action Listener:
public void actionPerformed(ActionEvent e) {
if(e.getActionCommand().equals("About")) {
System.out.println("About");
}
}
I'm running it in Eclipse on a Mac if that matters.

Control-A and Control-P are both keystrokes that may already be intercepted, depending on your platform and depending on what has keyboard focus. Control-A may already be intercepted and interpreted as "select all", and Control-P may already be intercepted and interpreted as "paste".
What if you select a less commonly-used keystroke instead of "Control-A", such as "Control-Shift-A" or "Control-B"? Here's a modified version of your code that uses Control-Shift-A instead of Control-A:
menuItem = new JMenuItem("About");
menuItem.setActionCommand("About");
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, Event.CTRL_MASK | Event.SHIFT_MASK));
menuItem.setMnemonic(KeyEvent.VK_A);
menuItem.addActionListener(this);
menu.add(menuItem);
I tested this change on my own system using the JMenu demo from the Swing tutorial, and I found (exactly as you did) that registering Control-A as the accelerator had no effect. However, registering Control-Shift-A as the accelerator worked perfectly.

not sure if it will help, but you're using Event.CTRL_MASK instead of KeyEvent.CTRL_MASK

Related

Allow user to redefine hotkeys for Swing during runtime Java

I have a Java application that contains a lot of features, and to make life easier for the user, I have set up numerous mnemonics and accelerators. For instance, I have a JMenuItem that allows the user to save the state of the application, witht he following code:
JMenuItem saveItem = new JMenuItem("Save");
saveItem.setMnemonic('S');
saveItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_MASK));
This works as desired, but now I would like to give the user an option to change the hot keys. While CTRL + s would seem like a fairly obvious hot key to stick with, there are many features that use these short cuts, and simply picked Save as an example.
I have a JButton that I have arranged for testing purposes that allows the user to enter in a new shortcut when clicked. I was thinking that I would simply try and capture the keys that the user holds down (InputEvent) and presses (KeyEvent). I also though it might be smart to force the use of an InputMask to avoid complications in Text Fields and the like.
What I am wondering is: What is the best way to capture the new input that the user enters? I have looked up information regarding KeyBindings and they look right for the job, but the main issue I see is actually capturing the keys and saving them.
Sounds like you need to setup a KeyListener. When the user presses/releases a key, it triggers a KeyEvent from which you can retrieve the main key pressed (e.g. S) and the mask/modifiers (e.g. CTRL+SHIFT).
From there you can create a KeyStroke object and set this as the new accelerator of your menu.
public void keyReleased(KeyEvent e){
KeyStroke ks = KeyStroke.getKeyStroke(e.getKeyCode(), e.getModifiers());
menuItem.setAccelerator(ks);
}
The thing is you probably want this key listener to be removed right after the key released event, to avoid multiple keystrokes to be captured. So you could have this kind of logic:
JButton captureKeyButton = new JButton("Capture key");
JLabel captureText = new JLabel("");
KeyListener keyListener = new KeyAdapter(){
public void keyReleased(KeyEvent e){
KeyStroke ks = KeyStroke.getKeyStroke(e.getKeyCode(), e.getModifiers());
menuItem.setAccelerator(ks);
captureText.setText("Key captured: "+ks.toString());
captureKeyButton.removeKeyListener(this);
}
};
ActionListener buttonClicked = new ActionListener(){
public void actionPerformed(ActionEvent e){
captureKeyButton.addKeyListener(keyListener);
captureText.setText("Please type a menu shortcut");
}
};
captureKeyButton.addActionListener(buttonClicked);

java: TrayIcon right click disabled on Mac OsX

I'm trying to develop a Mac OsX app provided by a system tray icon, so after the first attempt with the simplest code to achieve it I noticed that every apps tray icon's (both system and user apps) on mac osX (10.8) allows to activate the relative popup menu with both left and right click on it but with my project only the left (MouseEvent.BOTTON1) button causes the popup menu to pulldown. Here's my code:
public class SystemTrayDemo
{
private SystemTray tray;
private TrayIcon tray_icon;
public SystemTrayDemo()
{
if (!SystemTray.isSupported())
{
JOptionPane.showMessageDialog(null, "System tray not supported!");
return;
}
else
tray = SystemTray.getSystemTray();
final PopupMenu popup = new PopupMenu();
MenuItem exit = new MenuItem("Exit");
exit.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if (tray != null)
{
tray.remove(tray_icon);
System.exit(0);
}
}
});
popup.add(exit);
//add tray icon
tray_icon = new TrayIcon(getIcon("images/wifi.png"), "Open documents...", popup);
tray_icon.setImageAutoSize(true);
try
{
tray.add(tray_icon); // adds icon
}
catch (AWTException ex) {}
}
private Image getIcon(String name)
{
URL _url = getClass().getResource(name);
return new ImageIcon(_url).getImage();
}
public static void main(String args[])
{
new SystemTrayDemo();
}
}
but how I already said, only through left mouse button click.
So during a further attempt I've tried to mimic the behavior of the tray icons of every other apps using a MouseListener and firing a left button event on right click event using dispatchEvent() method like so:
public static void fireMouseEvent(Component c)
{
MouseEvent me = new MouseEvent(c, // which
MouseEvent.MOUSE_CLICKED, // what
System.currentTimeMillis(), // when
MouseEvent.BUTTON1_MASK, // no modifiers
0, 0, // where: at (10, 10}
1, // only 1 click
true); // popup trigger
c.dispatchEvent(me);
}
the event will handled by the mouse listener but obviously TrayIcon Class is not a Component subclass and therefore the source of MouseEvent is null and I get a NPE. Here's my MouseListener:
class MouseAdapt extends java.awt.event.MouseAdapter
{
public void mouseClicked(java.awt.event.MouseEvent me)
{
int button = me.getButton();
if(button == java.awt.event.MouseEvent.BUTTON3)
{
fireMouseEvent(me.getComponent());
}
}
}
try
{
tray.add(tray_icon); // aggiungi l'icona
tray_icon.addMouseListener(new MouseAdapt());
}
catch (AWTException ex) {}
Sorry for my english, I hope that someone who have ever had some experience with that kind of projects can help me. I've searched for hours but with no luck. Thank You for your help.
Edit: There's now a library working to fix all of this here: https://github.com/dorkbox/SystemTray
to activate the [TrayIcon] relative popup menu with both left and right click
This is simply not possible on Mac + Java currently. Using reflection to invoke the underlying triggers doesn't seem to help. This is a bug.
https://bugs.openjdk.java.net/browse/JDK-8041890
only the left (MouseEvent.BOTTON1) button causes the popup menu to pulldown. Here's my code
Even this is broken in some Java versions (7u79), fixed with an upgrade...
https://bugs.openjdk.java.net/browse/JDK-7158615
Cross-Platform TrayIcon Support:
Albeit slightly off-topic, I wanted to add, some projects use a JXTrayIcon to accomplish some fancy drop-down menus in Linux/Windows, etc. These also cause problems on Mac despite a click-bug it already suffers from today as well as bugs with Gnome3 requiring a completely separate hack. But on Mac, any attempt to use the decorated menus causes the menu to linger and is a very bad experience for the end-user. The solution I settled on was to use AWT for Mac, Swing for everything else. The Java TrayIcon support is in dire need of a rewrite. JavaFX claims to help this initiative, but it's staged for Java 9. In the mean time, I'm sticking to OS-dependent hacks.
Related Tray Issues for Other Platforms
Furthermore, some Linux distributions like Ubuntu have removed the tray icon by default in the Unity desktop, causing further headaches. https://askubuntu.com/a/457212/412004
In addition, the transparency of the icon is replaced with a gray color on Gtk/Gnome or Qt/KDE powered desktops (Both OpenJDK and Oracle JRE suffer this)
https://stackoverflow.com/a/3882028/3196753
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6453521
In addition, Gnome3 powered desktops may show it in the wrong corner, not at all, or it may show but be unclickable (Both OpenJDK and Oracle JRE suffer this)
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=660157
https://bugzilla.redhat.com/show_bug.cgi?id=1014448
In addition to that, high-DPI screens on Windows have a bug that draws the icon incorrectly: Windows 8 Distorts my TrayIcon
So in summary, the state of the System Tray in Java is OK, but due to the combination of factors is quite fragmented and buggy in JDK6, JDK7 and JDK8.

Text Missing On Checkbox Component for Swing After Adding Action

I'm writing a simple Swing app. I tried adding a checkbox as listed below. Once I added the actionHandler loadPickers the name Foo disappeared from where it was sitting next to the right of chckbxNewCheckBox. I tried adding a call to setHideActionText(), but now nothing displays.
JCheckBox chckbxNewCheckBox = new JCheckBox("Foo");
chckbxNewCheckBox.setToolTipText("");
chckbxNewCheckBox.setName("");
chckbxNewCheckBox.setHideActionText(true);
chckbxNewCheckBox.setAction(loadPickers);
mainPanel.add(chckbxNewCheckBox, "flowy,cell 0 1");
If I change it to this it works properly. I see the text "Foo".
JCheckBox chckbxNewCheckBox = new JCheckBox("Foo");
chckbxNewCheckBox.setToolTipText("");
chckbxNewCheckBox.setName("");
chckbxNewCheckBox.setHideActionText(true);
chckbxNewCheckBox.setAction(loadPickers);
chckbxNewCheckBox.setText("Foo"); //THIS DOES NOT WORK IF IT COMES BEFORE SET ACTION
mainPanel.add(chckbxNewCheckBox, "flowy,cell 0 1");
I've included the action here for completeness. Why does it work this way? Am I missing something here? Currently I'm using the WindowBuilder plugin for Eclipse with the Mig layout system (which I really like). Unfortunately I haven't figure out if there's a way to make WindowBuilder use the .setText() method instead of using the constructor. Any help on what I'm doing wrong, any insight on why this behavior exists like this, or a good workaround for WindowBuilder would be great.
private class LoadPickers extends AbstractAction {
public LoadPickers() {
//putValue(NAME, "SwingAction_2");
putValue(SHORT_DESCRIPTION, "Some short description");
}
public void actionPerformed(ActionEvent e) {
}
}
As explained in the JavaDoc of AbstractButton.setAction:
Setting the Action results in immediately changing all the properties described in Swing Components Supporting Action. Subsequently, the button's properties are automatically updated as the Action's properties change.
So all the following properties can be impacted by setting an action:
enabled
toolTipText
actionCommand
mnemonic
text
displayedMnemonicIndex
icon (NA for JCheckBox)
accelerator (NA for JCheckBox)
selected

Desktop.browse() opens multiple windows

We have the following code running in an applet running in JRE 1.6.0_26.
Desktop.getDesktop().browse(new URI("www.google.com")
On some Windows 7 64-bit, IE8 machines this command opens two windows but not on others which should be the same setup.
Does anyone have any idea what would cause this?
I strongly suspect this was just some coding carelessness (which I'm as guilty of as anyone else).
Consider the following code:
JButton myButton1 = new JButton("Click 1");
myButton1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Desktop.getDesktop().browse(new URI("www.google.com"));
}
});
JButton myButton2 = new JButton("Click 2");
myButton1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Desktop.getDesktop().browse(new URI("www.google.com"));
}
});
Notice the bug here?
The intention was to assign one action to each button, but because of a careless copy/paste after the definition of myButton2, we mistakenly assign a second action to myButton1.
What will happen now is when the user clicks on myButton1, the first action will be invoked resulting in the display of a browser with www.google.com showing, and then the second action will be invoked resulting in either another tab in that window or a whole other window (depending on your browser setup).

Performing an action when an JMenuItem is clicked?

So i have made a simple program with a basic menu at the top of the frame, Now i just need to put actions behind each JMenuItem. Im struggling to work the code out though, Here is what i thought would work:
JMenu file_Menu = new JMenu("File");
JMenuItem fileExit = new JMenuItem("Exit Program");
file_Menu.add(fileExit);
fileExit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
JFrame hello = new JFrame("POPUP");
hello.setSize(100,75);
hello.setDefaultCloseOperation(hello.EXIT_ON_CLOSE);
hello.setVisible(true);
}
});
main_Menu.add(file_Menu);
This doesn't seem to work though, I thought that this code would create a small popup window when the menu item is clicked.
Can any spot the bug because i cant seem to.
Suggestion: Instead of adding a separate ActionListener, just use AbstractAction:
JMenuItem fileExit = new JMenuItem(new AbstractAction("Exit Program") {
public void actionPerformed(ActionEvent ae) {
JFrame hello = new JFrame("POPUP");
hello.setSize(100,75);
hello.setDefaultCloseOperation(hello.EXIT_ON_CLOSE);
hello.setVisible(true);
}
});
I'd also suggest, instead of setting EXIT_ON_CLOSE on the popup menu, you set it on the main frame of your application, and have the action simply call theMainFrame.dispose().
You got it working, but you have another problem.
Don't do this:
hello.setDefaultCloseOperation(hello.EXIT_ON_CLOSE);
When you close the pop-up frame, your entire JVM terminates. Consult JFrame.setDefaultCloseOperation javadocs for a more appropriate value.
Give an instance of Action (extend from AbstractAction) to JMenuItem
Based on the code you posted it looks like it should work, but we can't see the entire context of how the menu item is being used.
Did you debug your code (with a System.out.println) to see if the ActionListener is being invoked?
If you need more help post your SSCCE that demonstrates the problem.
Fixed it.
Forgot to add the actionPerformed method.

Categories

Resources