Menu mnemonic doesn't work [duplicate] - java

In SWT you can give any button a shortcut key simply by adding & in front of the letter in the button label. For example, if my button label is &Play, I can activate the button by hitting letter p on the keyboard.
In Swing, you can add a shortcut key using the mnemonic property. However, you need to hit alt+p to activate the button. This is really most appropriate for menu shortcuts. I want to activate the button with a letter press and no alt modifier.
I've seen this post on how to do it, but it seems absurdly complicated. Is there an easier way to do this?
http://linuxjavaprogrammer.blogspot.com/2008/01/java-swing-jbutton-keyboard-shortcuts.html
Update: After #camickr suggestion, I ended up using this code. I couldn't find any clear and simple example online, so hopefully this will help people out.
// play is a jButton but can be any component in the window
play.getInputMap(play.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_P, 0), "play");
play.getActionMap().put("play", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
playActionPerformed(e); // some function
}
});

Yes, Swing was designed to use Key Bindings. So instead of adding an ActionListener to the button you add an Action. Then that Action can be shared by the button or a menu item. You can also assign any number of KeyStrokes to invoke the Action by using the KeyBindings. The tutorial also has a section on Actions which explains why using an Action is beneficial.
JComponent has a registerKeyboardAction(...) method which basically does the InputMap/ActionMap bindings for you, but it also has to wrap the ActionListener in a wrapper Action so its preferrable for you to do you own bindings.

Further to camickr's answer, I am now using a little utility function like this:
public static void clickOnKey(
final AbstractButton button, String actionName, int key )
{
button.getInputMap( JButton.WHEN_IN_FOCUSED_WINDOW )
.put( KeyStroke.getKeyStroke( key, 0 ), actionName );
button.getActionMap().put( actionName, new AbstractAction()
{
#Override
public void actionPerformed( ActionEvent e )
{
button.doClick();
}
} );
}
Now to set the keyboard shortcut for a button I just do:
clickOnKey( playButton, "play", KeyEvent.VK_P );

I had a similar problem with a dynamically constructed (based on data input) form and just ended up attaching a keyListener action to the buttons. On form construction I parse the Component tree for the buttons and attach the listener. The listener than also parses the tree and matches the keypress with the appropriate button (via the text in the button), since I have no idea which one will have focus at any given time, and fires the button doClick... It's ugly, feels hackish, and has got to be a bit processor intensive, but it allows the flexibility I need for this particular dynamic form...

Related

SWT Keylistener is not triggered

I have a SWT GUI, containing different elements (Text, Buttons, Labels...) which are themselves in different Composites.
I would like to make the navigation easier using some keybindings such as "Alt+c" to call the Cancel Button, "Alt+f" to call the finish button etc... When using a KeyListener on a specific component, the listener is triggered, but it implies that the component has the focus (and this is not very convenient !).
So I tried to register the listener on the shell itself, but the result is the same and nothing is triggered.
How should I proceed in order to get my listener triggered no matters what element is currently focused ?
Any hint would be appreciated.
Thanks for reading.
Edit
Regarding the comments, I tried to add the keylistener recursively to all the composites of the GUI, and it's working. However, I guess there is probably a "clever" way to do it.
You can use the Display addFilter or addListener methods to add a listener which is always called.
Display.getDefault().addListener(SWT.KeyDown, new Listener() {
#Override
public void handleEvent(final Event event) {
// TODO handle event
}
});
These listeners use the lower level Listener interface rather than KeyListener.
addFilter is similar to addListener but is called earlier and can change the event.
The easiest way is to add a event filter to the display:
Here is an example I use to activate a search field when a user types command-F in our main application window.
Display.getCurrent().addFilter(SWT.KeyDown, event -> {
// Only respond to key events for our shell.
if (getShell().equals(Display.getCurrent().getActiveShell())) {
// Activate the focus for our search widget when user types 'f'
// (control-f, command-f, or just f)
if (event.keyCode == 'f') {
if (!searchField.isFocusControl()) {
searchField.setFocus();
}
}
}
});

How to check if and which mouse button is pressed in Swing

How can I check if currently any mouse button is pressed and if so, which one it is?
The thing is that I need to use this kind of information in MouseListener.mouseEntered(). I checked MouseEvent but I could not find the method which would help me.
The getButton() method seems to only return value if there has been change in buttons' state.
Is there a way to find this out without manually keeping track of this somehow vie MouseListener.mousePressed()/mouseReleased() methods.
How can I check if currently any mouse button is pressed and if so, which one it is?
Presumably you want to invoke specific code depending on the button pressed so you can do something like:
if (SwingUtilities.isLeftMouseButton(...))
// do something
You could start by looking at How to write a Mouse Listener and the JavaDocs for MouseEvent in particular, the getButton method.
However, there are cross platform considerations that need to taken into consideration, which are overed by SwingUtilities.isLeftMouseButton and equivalent methods...
This will solve your problem
long eventMask = AWTEvent.MOUSE_MOTION_EVENT_MASK + AWTEvent.MOUSE_EVENT_MASK;
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
public void eventDispatched(AWTEvent e) {
System.out.println(e.paramString()+"-"+e.getSource());
}
}, eventMask);
This is a Global Event Listeners.
Get the source and button from AWTEvent and do whatever you want to perform.

Textfield loses focus when user clicks on checkbox (Java Swing)

So I'm using a JPasswordField to get the user input, and then give instantaneous feedback regarding the strength of the entered password. My problem is that if the user clicks on the 'hide' checkbox, the string in the textfield isn't immediately masked by '●', but works only when the textfield regains focus. I've tried to use component.getFocus within the mouseListener, but it doesn't seem to work.
Here's what this particular listener looks like:
inputT.addMouseListener(new MouseAdapter(){
#Override
public void mouseClicked(MouseEvent hideClicked){
if (hideC.isSelected()){
inputT.setEchoChar('•');
inputT.requestFocus();
}
if (!hideC.isSelected()){
inputT.setEchoChar('\u0000');
inputT.requestFocus();
}
}
});
Show the feedback to the user in a different field than the password field that they are typing into. Ideally a separate read only component that is to the right of the password in your GUI. Your password strength feedback would then be updated by a listener on the password field, but the JPasswordField could then just work like normal.
From the JavaDoc: http://docs.oracle.com/javase/7/docs/api/javax/swing/JComponent.html#requestFocus%28%29
public void requestFocus()
Requests that this Component gets the input focus. Refer to Component.requestFocus() for a complete description of this method.
Note that the use of this method is discouraged because its behavior is platform dependent. Instead we recommend the use of requestFocusInWindow(). If you would like more information on focus, see How to Use the Focus Subsystem, a section in The Java Tutorial.
Also, as MadProgrammer pointed out - your listener is on the JPasswordField instead of the JCheckBox.
Don't use mouse listener. For doing on selection, use ItemListener:
checkBox.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent evt) {
if(evt.getStateChange()==ItemEvent.SELECTED)
jPasswordField1.setEchoChar((char)0);
else jPasswordField1.setEchoChar('*');
}
});
Well, the above code works perfectly for me.
Start by attaching a ActionListener to the the checkbox, this means that user can click or press the space bar to activate the check box
In the actionPerformed method, check the state of the checkbox and the required changes.
Use JPasswordField#selectAll or JPassword#requestFocusInWindow (usually I do it the other way round ;)). If these do not work, you might even consider using JPassword#repaint to force the field to repaint

Extending a java swing button?

I want each JButton to also have a number or id associated with it. That is why I decided to extend the JButton class to make a class SuperJButton.
How do I include the value of the id/number in the action event generated when this button is clicked so that the class which responds to this action can access the id ?
Another alternative which doesn't require sub-classing, could be to use JComponent.putClientProperty(Object key, Object value) to store the ID associated with your button.
It can be retrieved using getClientProperty(Object key).
public void actionPerformed(ActionEvent e)
{
JComponent comp = (JComponent)e.getSource();
KeyObject kObj = (KeyObject)comp.getClientProperty("button.id");
}
That might be a bit more flexible as you can attach this ID to every button without the need to use an application specific code e.g. when using a GUI builder where it's a bit complicated to change the creation code for a button, or when you need to use already existing components.
You don't have to change the Action event.You can do this,
SuperJButton jButton = (SuperJButton) actionEvent.getSource();
jButton.getId()
jButton.getNumber()
From MVC point of view: JButton is a view, and JButton class is not better place to something like id. Much better place for an id is in your own ButtonModel implementation.

Shortcut key for jButton without using alt key

In SWT you can give any button a shortcut key simply by adding & in front of the letter in the button label. For example, if my button label is &Play, I can activate the button by hitting letter p on the keyboard.
In Swing, you can add a shortcut key using the mnemonic property. However, you need to hit alt+p to activate the button. This is really most appropriate for menu shortcuts. I want to activate the button with a letter press and no alt modifier.
I've seen this post on how to do it, but it seems absurdly complicated. Is there an easier way to do this?
http://linuxjavaprogrammer.blogspot.com/2008/01/java-swing-jbutton-keyboard-shortcuts.html
Update: After #camickr suggestion, I ended up using this code. I couldn't find any clear and simple example online, so hopefully this will help people out.
// play is a jButton but can be any component in the window
play.getInputMap(play.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_P, 0), "play");
play.getActionMap().put("play", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
playActionPerformed(e); // some function
}
});
Yes, Swing was designed to use Key Bindings. So instead of adding an ActionListener to the button you add an Action. Then that Action can be shared by the button or a menu item. You can also assign any number of KeyStrokes to invoke the Action by using the KeyBindings. The tutorial also has a section on Actions which explains why using an Action is beneficial.
JComponent has a registerKeyboardAction(...) method which basically does the InputMap/ActionMap bindings for you, but it also has to wrap the ActionListener in a wrapper Action so its preferrable for you to do you own bindings.
Further to camickr's answer, I am now using a little utility function like this:
public static void clickOnKey(
final AbstractButton button, String actionName, int key )
{
button.getInputMap( JButton.WHEN_IN_FOCUSED_WINDOW )
.put( KeyStroke.getKeyStroke( key, 0 ), actionName );
button.getActionMap().put( actionName, new AbstractAction()
{
#Override
public void actionPerformed( ActionEvent e )
{
button.doClick();
}
} );
}
Now to set the keyboard shortcut for a button I just do:
clickOnKey( playButton, "play", KeyEvent.VK_P );
I had a similar problem with a dynamically constructed (based on data input) form and just ended up attaching a keyListener action to the buttons. On form construction I parse the Component tree for the buttons and attach the listener. The listener than also parses the tree and matches the keypress with the appropriate button (via the text in the button), since I have no idea which one will have focus at any given time, and fires the button doClick... It's ugly, feels hackish, and has got to be a bit processor intensive, but it allows the flexibility I need for this particular dynamic form...

Categories

Resources