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,
Related
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
Note: see the edit (save some time reading)
I'm trying to make my mind-mapping program respond to shortcuts like CTRL+RIGHT (reordering nodes) and TAB (insert child at next indent level). I have a JPanel that handles all of the keystrokes. It resides inside of a JTabbedPane that might be the cause for Key Bindings not working. I've chickened out and decided to just use KeyListener.
The problem is that with the aforementioned key combinations, Swing automatically shifts the focus to some other component. I'd rather not manually put setFocusable(false) everywhere. How can I disable these shortcuts altogether in such a way that the focus will not be shifted, and the relevant KeyEvents will still be sent to my JPanel?
Edit:
I used the following code:
for (int id : new int[] {KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS})
setFocusTraversalKeys(id, Collections.EMPTY_SET);
to disable the default traversal keys (particularly TAB.)
Now the issue is actually why CTRL+UP causes a loss of focus. When pressing CTRL+DOWN, for instance, it's fine. The component behaves as expected. But with CTRL+UP, it works as expected and then focus is shifted/lost somehow. Can anyone say what CTRL+UP means and how to disable it wherever it is? Google isn't helping.
KeyBinding are used for all KeyEvents implemented in Swing APIs, maybe there is/are conflict
is required to override required KeyBindings, change used Keys, set to null, e.i. depends of your requirements
list of KeyBindings by #camickr
I need help working getFocusOwner(). I have a Sudoku game that I made in Java and I want to add arrow key navigation to the program. I did some research and found that using the focus system would be the best way (If it's not, please give me a better way and I can research that).
Okay, so for testing purposes, I'm trying to set focus to SetField, a custom class extending JTextField(Custom because I wanted to disable any inputs that weren't numbers). It has been set to focusable. I called requestFocusInWindow() on the SetField in the middle of the grid, and the focus is set to that component. The problem arises when I try and retrieve the component that has focus.
This is what I'm doing to test the getFocusOwner() method:
sGrid[40].requestFocusInWindow();
try{
System.out.println(this.getFocusOwner().getClass().getSimpleName());
} catch(NullPointerException e){
e.printStackTrace();
}
No matter what component I try this on, I always get the null pointer exception. I tried it with the JButtons, JLabels, and even on JPanels in my program. The focus is set to the component though. I can see the caret blinking in the intended SetField. Is there something I'm doing wrong? Thanks in advance for any help.
Instead of a custom component to only allow numbers, just us a JFormattedTextField.
Do you need to even determine which component has focus, why not add a KeyListener, MouseListener? I am not exactly sure what you doing with the focus but it seems strange.
I want to add arrow key navigation to the program.
You should be using Key Bindings. Create a basic "ChangeFocusAction". You will need 4 instance of this class that you can map to a KeyStroke.
Assuming you have a array of 81 text fields your Action could be created with an integer value that tells the Action how to change focus. For example:
right = -1
left = 1
up = -9
down = 9
The source of the ActionEvent will contain the text field that has focus. Then you search the arry to find the offset of that text field. Then you add the int value from above to the index and request focus on that component.
Just found out the problem. For anyone else that's having a problem with this, try using (Window).getMostRecentFocusOwner(). This worked for me.
what is the easiest way to listen for key presses from the user? Specifically I am writing an image viewer program that uses a JFileChooser to select images and on the left side, a JList that shows the contents of the director. I would like to make the arrow kets (left/right) move to the next/previous file.
Thank you in advance.
It sounds like you need a KeyListener. The linked tutorial also talks about focus, which will be important to ensure your key events are trapped by the right handler.
Swing was designed to use Key Bindings.
In fact a JList already supports the up/down keys to move to the next item in the list. You can easily map these Actions to the left/right keys.
I'm working on a map editor for my college project. And I had a problem that the map panel is not listening key event while it should.
This happens when I add a ToolBarPane (which extends JPanel) with JComponent such as JButton, JComboBox that implements ActionListener on it AND the map panel (which extends the JPanel) together on to the Frame (I used BorderLayout). I have System.out.println statement to test if the key press is received, and it's not printing, if I remove the ToolBar, the key listener works again, so is the mouseListenner is disabled just like the keyListener, which means I can't handle press events etc, but the mouseListener works fine and I can still handle mouse move event.
Here is a screen shot how it works without the ToolBarPane
http://img684.imageshack.us/img684/3232/sampleku.png
note that you can use the mouse to put images on the map, you can also select images using the mouse just like a laser tool, and by pressing number key you can switch between different images, this works fine until I add the ToolBarPane which shows like this:
img291.imageshack.us/img291/8020/failve.png
(please add http before that, I can only post one hyperlink)
(I can't post images here because I'm a new user)
With the ToolBarPane on I was no longer able to handle the key event.
I guess it might by that the focus as been transferred to that panel somehow, but not sure at all.
Does and body know this and can help me out?
Thanks very much
I suggest you use the InputMap and WHEN_ANCESTOR_OF_FOCUSED_COMPONENT or something similar. Excerpt from How to Use Key Bindings:
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
The component contains (or is) the component that has the focus. This input map is commonly used for a composite component
That has worked very robustly for me. Have a look at my other post for more information and actual code examples:
Keyboard input for a game in Java
or this tutorial:
Swing: Understanding Input/Action Maps
You should NOT be using a KeyListener.
Swing was designed to use Key Bindings which is far more flexible. Check out my quick summary of Key Bindings which also includes a link to the Swing tutorial which conains far more detail.
(I can't post images here because I'm a new user)
An image doesn't help much anyway. If you need more help post your SSCCE which shows the problem (after trying the above suggestion).