I asked this question a little earlier, but maybe some of you were asleep, as where I live at the time it was probably very early in silicon valley.
My program has assigned new functions to the arrow keys, but for the very last part of the Swing display's presentation I need them to function normally within a TextArea, moing the cursor and such.
Is there a way to restore to defaults, or through an AbstractAction assign simple movement of the cursor once again?
The original answer I gave you showed how to replace the Action. If you need to restore the default Action then it is probably easier to create a new InputMap and ActionMap entry for the Action. The Key Bindings link I gave you shows how to do this.
Then when you need to restore the default Action you can use:
textField.getInputMap().put(keystroke, "none");
This will cause the original InputMap to be search again.
Another approach it to save the Action before you update the ActionMap with the custom Action. Something like:
Action original = textField.getActionMap().get(...);
Reread the Key Bindings link to better understand the usage of the InputMap and ActionMap.
Related
My Netbeans RCP application has a global key binding on the SPACE key which triggers action MyAction. It works fine.
My app contains an editable JSpinner. If user presses SPACE while he's editing the spinner value, it also triggers MyAction, and I don't want that.
I found a workaround with:
mySpinner.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke("SPACE"), "doNothing");
mySpinner.getActionMap().put("doNothing", new DoNothingAction());
But I will have other global key bindings in my app...
Is there a generic way to remove all key bindings in the JSpinner, without replicating the above code for each new key ?
Both InputMap and ActionMap have clear() methods that remove all existing bindings. You might not want to clear all the bindings though, because they include most probably arrow keys also which are used to select next previous values in spinner.
I am trying to get my application to respond to keyboard input. Eventually, I would like it to register ctrl+f and initiate a search, but I started simple and tried for the space bar. The Java tutorials on using Key Bindings got me this far, but no matter what I apply the key binding to, nothing registers. In the below code, panel is a JPanel and the others are assorted swing objects which have been added to panel.
Action ctrlF = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
System.out.println("Action performed");
}
};
panel.getInputMap().put(KeyStroke.getKeyStroke("SPACE"),"crtlF");
openStallsList.getInputMap().put(KeyStroke.getKeyStroke("SPACE"),"crtlF");
openStalls.getInputMap().put(KeyStroke.getKeyStroke("SPACE"),"crtlF");
stallScroller.getInputMap().put(KeyStroke.getKeyStroke("SPACE"),"crtlF");
assignLabel.getInputMap().put(KeyStroke.getKeyStroke("SPACE"),"crtlF");
tenantInfo.getInputMap().put(KeyStroke.getKeyStroke("SPACE"),"crtlF");
unitSpinner.getInputMap().put(KeyStroke.getKeyStroke("SPACE"),"crtlF");
buildingAddress.getInputMap().put(KeyStroke.getKeyStroke("SPACE"),"crtlF");
buildingLogo.getInputMap().put(KeyStroke.getKeyStroke("SPACE"),"crtlF");
What am I missing here? Does it have something to do with focus? There are a couple of assorted labels and buttons which are not included on that list. Is there any way to get panel to register all of the input from all of it's children?
Thanks
First, you need bind a KeyStroke to some kind of "key". Now personally, it's eaiser to specifiy the virtual key then using a String, as the String value can be a little temperamental, but that's me
panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0),"crtlF");
Next, you need to bind the "key" to an Action
panel.getActionMap().put("crtlF", ctrlF);
See How to use key bindings for more details.
The next problem you will have is the component will need to be focused before the key binding can be triggered
You could try and get the InputMap with a different focus requirement using either WHEN_ANCESTOR_OF_FOCUSED_COMPONENT or WHEN_IN_FOCUSED_WINDOW which will allow you to change the focus level required by the component in order for the key binding to be triggered.
i.e.,
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = panel.getInputMap(condition);
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0),"crtlF");
//... etc
I have two Jtables Emplyoee and Manager.If I enter on Emplyoee Table then focus should go on Manager table.I used ChangeSelection but it is not working.
The simplest solution I can think of is to attach a key binding to the Employee table that moves focus to the Manager
Take a look at Key Bindings for more details.
Within your action handler, you would need to call requestFocusInWindow using a instance of the Manager table.
I did look at the focus sub system, but this would effect the entire focus root, which I felt was beyond the scope of what you were asking.
Updated
You could change the focus traversal keys, but this will only move focus to the next focusable component...
Set forward = new HashSet(table.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS));
forward.add(KeyStroke.getKeyStroke("ENTER"));
table.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, forward);
//Set backward = new HashSet(table.getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS));
//backward.add(KeyStroke.getKeyStroke("shift TAB"));
//table.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, backward);
When I hit the enter key into a JTextField and I'm pressing one modifier key (like Ctrl or Alt) the ActionEvent is not fired and thus I can't check the modifier key just pressed.
Why is it a bug?
For Swing widgets, key binding should be done through InputMap and ActionMap (although the "obsolete" registerKeyboardAction is simpler). See Keyboard Bindings in Swing in the old Swing Connection, and the JComponent API docs.
The Pluggable Look & Feel rather gets in the way of mapping input events onto actions. Exactly what happens with ActionEvent is up to the current PL&F. Application code directly registering KeyListener generally isn't a good idea in Swing. Some components are made up of other smaller components, meaning InputEvents may or may not get passed on. Input events may get interpreted to perform more than one operation. Generally the whole thing is a mess.
I've a problem with setAccelerator(). Right now, I have the code that works for Ctrl+X for DELETE operation. I want to set the accelerator to Shift+Delete as well for same JMenuItem.
My code as follows:
JMenuItem item = new JMenuItem(menuText);
item.setAccelerator(KeyStroke.getKeyStroke(
KeyEvent.VK_X, KeyEvent.CTRL_MASK));
item.setAccelerator(KeyStroke.getKeyStroke(
KeyEvent.VK_DELETE, KeyEvent.SHIFT_MASK));
but this is working only for Shift+Delete operation. Seems it is overriding the Ctrl+X operation. Can we make both these keystrokes work at the same time?
Please guide.
Yes it can be done. Behind the scenes the setAccelerator() is just creating a Key Binding, however as you noticed the second binding replaces the first.
So, you need to create an Action (not an ActionListener) to add the to the menu item. Read the section from the Swing tutorial on How to Use Actions for more information. Now that you have created the Action, you can share the Action with another KeyStroke by manually creating a Key Binding. You can read the section from the Swing tutorial on How to Use Key Bindings for a detailed explanation. Or you can read my blog on Key Bindings which give some simple code examples.
This second binding will not show up on the menu item itself.
From: http://java.sun.com/j2se/1.4.2/docs/api/java/awt/AWTEvent.html
The masks are also used to specify to which types of events an AWTEventListener should listen.
So you can combine the mask for two keys, but not the KeyEvents.
item.setAccelerator(
KeyStroke.getKeyStroke(
KeyEvent.VK_X, KeyEvent.CTRL_MASK + KeyEvent.SHIFT_MASK));
A workaround solution would be to catch the KeyEvent in the middle (after your component fired it, but before your listeners will act on it) and check, whether its one of the two combinations. Then fire one event, on which you programmatically agree to represent the action you wanted.
The second call indeed overrides the accelerator. If the method starts with set, there will be only one. If the method starts with add, you can have more than one (for example for a number of listeners).
If you want multiple keystrokes to do the same, I think you should add a keyListener to the top frame (or panel, dialog, ...) which invokes the action listeners added to the menuItem.