Forward all key events to parent JFrame - java

I need that all the key events (including Carriage Return, TAB, etc) generated by all child or grandchildren components of a JFrame, to be listened for a single method inside this JFrame. I have googled a lot, but I have not been able to find the solution I need. I found a partial solution using "InputMap/ActionMap", but it only allows to add particular KeyStrokes on the InputMap, but I need all possible Key Strokes to be forwarded to the parent JFrame.
Thanks.
(I saw this thread, but I was expecting a solution within the Swing API, specifically to address this subject.

Check out Global Event Listeners which gives you a couple of choices:
Use an AWTEventListener.
Us a KeyEventPostProcessor.

Related

Remove/disable/override Swing's focus traversal keys

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

Listeners in forms with JComponents

Right now, when I have a form with many JComponents, mainly JTextFields, JTextAreas, JComboboxes, JCheckBoxes and JButtons and want to control their behaviour, for instance the change of focus after a certain key was released, I do the following:
I put all my components in a JComponent[] and cycle through it, adding the appropriate listener. When an event is registered by said listener, I check with "instanceof" what kind of JComponent fired the event and assign the proper reaction.
I use this method for instance to cycle with VK_ENTER through the form, or to "firePropertyChange(..)" after a DocumentListener fires, or to add UndoRedoListeners and so on.
My question : is there a better way to do this and if yes, can you explain to me the benefits ?
but my question refers to the general practice of putting all
JComponents in an array and cycling through them for every listener
and every fired event. It works fine enough, but it feels a bit
"uneconomic",so I wanted to know if it is recommended practice, or if
there is a better way of doing it.
I usually write a custom listener (often as an anonymous class) per type/ instance if I have type/ instance specific behavior so that I can avoid instanceof and other other checks.
You'll want to customise the focus tranfersal system.
Take a look at How to Use the Focus Subsystem, in particular Customizing Focus Traversal

Binding events between JComponent and ComponentUI delegate

I have started trying to create normal MVC Swing components. I have no problems with M and C, but V had thrown at me one problem which I cannot normally solve.
The problem is: Controller is main class of the component (MyComponent, for example), and it extends JComponent. View is ui delegate (MyCompanentUI) extended from ComponentUI class. All what delegate does is adds JTextField in MyCompanent and provides data binding between MyComponentModel and this field. It works just fine. But how I can bind events from JTextField to MyComponent?
If user wants to handle some events he adds listeners to MyComponent, but all real events (mouse, focus, keys, etc.) intercepted by JTextField, about which user does not really knows.
So is there any normal way to do this, except catching events and translate it to original component by hands? Or is there another way to create delegate and I just really do it all wrong?
UPD:
Thanks for your response, trashgod.
But I had something different in my mind. I was talking about something like "events inheritance", like in the case of "inheritsPopupMenu" method. So that then key, focus or mouse event happens to the component one does not process it itself, but directly transfer it to parent component. But it seems impossible, because I have noticed JSpinner has exactly the same issue - you cannot get almost any event notification from this very component.
If you are writing your own JComponent subclass and want to allow for custom UI delegates, I'd start with Kirill Grouchnikov's How to Write a Custom Swing Component.
If you are writing a composite that includes an existing JComponent subclass, such as JTextField, see if you can leverage the existing Action instances described in How to Use Key Bindings. ScrollAction is an example. You can learn the names of such actions from the component's source(s) or using #camickr's handy utility seen in the article Key Bindings.

Capturing "Tab" key press by both the focused component and its container

Is there a way to propagate a key press from say a JTextField to its container's KeyListener implementation?
So in effect, the keypress would be acted upon by both the text field and the JPanel. Right now the text field is consuming the key press so is nonexistent to the JPanel underneath.
In Swing, the tab key is used to change the focus from one component to another. The article Validating Input discusses InputVerifier, which may help you do what you want.
The question is why do you want to do this? What is your actual requirement as oppose to your attempted solution. Having an event handled by two components is generally not a good idea.
In general you should not use KeyListeners. Swing was designed to use Key Bindings. However, in this case it won't help because as mentioned earlier the focus subsystem handles the tab key.
If this is the only solution to your problem, then I think you can use KeyEventPostProcessor to listen for any KeyEvent. See Global Event Listeners for more info.

Can multiple accelerators be defined for a JMenuItem?

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.

Categories