I have a custom textfield class that extends the JTextField class in Swing.
I need to find a way to disable the default actions for Ctrl-A (select all), Ctrl-H (backspace) etc, so that the window containing the textfield can map these shortcuts to whatever it wants.
Any help would be greatly appreciated.
Okay, found the answer myself:
Added the following to an initilization method of the textfield class:
this.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.CTRL_MASK), "none");
The effect is that the textfield ignores the shortcut and lets the keystroke be passed along to the shortcut handler in the window.
How to make and remove key bindings would help you to implement.
To remove all of default key bindings, just dereference its parent InputMap.
jtextField.getInputMap().setParent(null);
But it remove all of key bindings so that you can't type any characters. JTextField's input has 3 parents. So you would be better with overriding specific key bindings as below.
InputMap inputMap = jtextfield.getInputMap();
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, Key_Event.CTRL_DOWN_MASK), "foo");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, Key_Event.META_DOWN_MASK), "foo");
Maybe you should deal with the KeyMap.
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 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.
OK here we go again. Steve has to program another non-standard set of key strokes.
We have an editable JTextPane embedded in a JScrollPane. This pane correctly handles the Up and Down arrow keys, but I can't figure out how. If I could figure out how, I could implement the nonstandard things I need to implement.
Specifically, because the PageDown key is globally mapped to doing another function we don't do the default actions for PageUp, PageDown,Ctrl-PageUp and Ctrl-PageDown. Instead we want to map these functions to the shifted arrow keys, not the ones on the numeric keypad.
Specifically in the JScrollPane class's ancestor input map ((InputMap)UIManager.get("ScrollPane.ancestorInputMap");) we add the
Shifted Down Arrow key to the Ancestor input map pointing to
the"scrollDown" action
Shifted Up Arrow key to the Ancestor input map pointing to the
"scrollUp" action
Shifted Left Arrow key to the Ancestor input map pointing to the
"scrollHome" action
Shifted Right Arrow key to the Ancestor input map pointing to the
"scrollEnd" action
None of these keystrokes do anything. I'vwe even overridden the processKeyEvent() and processKeyBinding() methods of JComponent to log what was going on, and I find that these methods are never fired by these keystrokes. Also, the plain standard up arrow and down arrow keystrokes do not fire these methods, even though these keystrokes do work.
So it seems clear that something else is handling these keystrokes. But what component is that?
And yes, the text pane does have focus when I am trying this.
reference version for Steve :-)
DU love this forum too,
SSCCE could opening any doors for volunteers on 2nd side. isn't it
As mKorbel correctly shows there is an action "page-up" and "page-down" (see 3rd screen). So just use ActionMap and replace the action with yours.
OK, trashgod was basically right. The solution was to use the KeyBindings names for the action. The delay in finding the right answer was due to a stray bit of code that was undoing the mapping elsewhere.
More specifically, we disable the default keystrokes in the JTextPane and then add them to the input map of the Scroll Pane, mapped to their new actions.
In the TextPane constructor
...
disableAction("caret-down"); // down arrow
disableAction("caret-up"); // up arrow
disableAction("selection-backward"); // shift-left-arrow
disableAction("selection-forward"); // shift-right-arrow
disableAction("selection-up"); //shift-up-arrow
disableAction("selection-down"); // shift-down-arrow
}
private void disableAction(String name) {
Action a = getActionMap().get(name);
if (a != null) {
a.setEnabled(false);
}
}
In the ScrollPane
import static javax.swing.KeyStroke.getKeyStroke;
import static java.awt.event.KeyEvent.*;
...
private void remapShiftedArrowKeys() {
InputMap map = (InputMap)UIManager.get("ScrollPane.ancestorInputMap");
map.put(getKeyStroke(VK_DOWN, SHIFT_DOWN_MASK), "scrollDown");
map.put(getKeyStroke(VK_UP, SHIFT_DOWN_MASK), "scrollUp");
map.put(getKeyStroke(VK_LEFT, SHIFT_DOWN_MASK), "scrollHome");
map.put(getKeyStroke(VK_RIGHT, SHIFT_DOWN_MASK), "scrollEnd");
}
note that we don't have to map shifted Up and Down keys because the JScrollPane already does what we want with those keys. It is simply enough to unmap them from the JTextPane. Whereas these other four keystrokes are completely non-standard and must also be remapped in the Scroll Pane.
Thanks for all your help!
Oh, and the actual answer is that the JTextPane normally handles those arrow keys of course. To do what I wanted I had to defeat that and map appropriately in the scroll Pane,
So far I've got ESC key to close the window, using the following code:
KeyStroke escapeKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false);
Action escapeAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
screen.dispose();
}
};
screen.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(escapeKeyStroke, "ESCAPE");
screen.getRootPane().getActionMap().put("ESCAPE", escapeAction);
But I am wondering how I would go about adding a CTRL+A event? I remember reading about a way where you set booleans for keypressed/released, but I don't see that working with this piece of code, so I am wondering how I can implement CTRL+A.
Thank You
It's the second parameter of the KeyStroke.getKeyStroke(...) method that matters, as you'll want to use the InputEvent.CTRL_DOWN_MASK there to let the KeyEvent.VK_A be a control-A.
e.g.,
KeyStroke ctrlAKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_A,
InputEvent.CTRL_DOWN_MASK);
I wouldn't worry about using the 3 parameter method that uses a boolean since you're more interested in key press, not key down or key release.
Regarding your comment:
Correction to my earlier comment. It works, if I make it let's say Ctrl+W. Ctrl+A just attempts to do its native "select all" function in a textfield in the frame. Any way to avoid that?
From the little I understand, this will be a problem if the component that has focus (such as a JTextArea) responds directly to the ctrl-A key press. To get around this, you can add the same binding to this component, but being sure to bind it to its InputMap that uses the JComponent.WHEN_FOCUSED; condition.