How to transfer focus a custom component when traversal keys are disabled? - java

I have created a custom JComboBox with a custom popup that implements the KeyListener. I wanted an item to be selected from the popup of the cmbBox on the press of either Tab or Enter hence I set the setFocusTraversalKeysEnabled(false) for both the combobox and the popup.
The problem with this approach is that now I have to add another KeyListener to the combobox when I use it in containers so as to shift the focus.
Can I fire a transfer focus event(hypothetically) or something like that within my custom JComponent which will transfer the focus in its parent component so that I dont have to add key listeners everywhere I use it. I have used transferFocus() but it is not transferring the focus.
I have not dirtied my hands on Key Bindings yet but is there a key binding to transfer the focus?
Thanks
I am trying to recreate a sscce but its proving difficult. Please bear.

Basic Listeners lifecycle is about to add required listener if is really needed, and remove Listener if is useless
I'd would be suggesting use KeyBindings, because this Listener is designated for Swing JComponents and sure you can (sure same as for KeyListener) add this listener to the concrete JComponent or its derivate(s)
you can add Listener to the derived popup on firePopupMenuWillBecomeVisible
you can add ItemListener to the derived JList
maybe not correct way but protect all defects implemented to the KeyListener, that only Focus owner can take events from keyboard, sure workaround for KeyBindings os more that settable and confortable
notice please read this answer

Related

Monitor interaction with child components of a top-level container [duplicate]

I have a Java swing application with several panel and transitions between them (button, inputs ...).
What I want now is to set a timeout for my whole application (that will logout the user on my software), and bring back the user to another JPanel (I don't need help for that part).
After some research I have found something that seems to work (not fully implemented atm), I'm adding Key, MouseMotion and MouseWheel listener to ALL my swing elements and reloading my timer for any user action.
I wanted to know if there is any built-in function that can handle such a situation or a nicer way to do it. Thanks
I'm adding Key, MouseMotion and MouseWheel listener to ALL my swing elements
You can check out Application Inactivity which does this using an AWTEventListener so you don't need to do it for all your components.
You provide the listener with an Action to invoke after your period of inactivity.

How to make a KeyListener trigger for all components of a JFrame?

I have a class, like so:
public class MyFrame extends javax.swing.JFrame implements KeyListener { ... }
In the constructor:
addKeyListener(this);
setFocusable(true);
This works as long as the window itself is in focus. If I focus on a component within that window, the key listener no longer listens. I want it so that whenever the window is the active window, but regardless on which specific sub-component the focus is on, the key listener will be triggered. I wish to keep focus traversal keys, for quality of life, but they're not critical.
How do I do this?
Preferably you would use the key bindings API for each component, you can use the key bindings to change the level of focus required to trigger the given action, for example, for when the component has focus, when the component is a child of a focused component or when it is contained within the focused window...
See How to Use Key Bindings for more details
Add the KeyListener recursively to the sub components.
Check this
How to get all elements inside a JFrame?
i hope this could help!

Design for a component with 2 listeners and 2 "setters" (Swing application)

I'm making a map editor using java swing for my tile based java game. the swing application has two major components, the "upper" component is the game map preview, and the "lower" component is modifyable properties of the map, like its height and width.
Currently the user types in to a jtextfield for the map width, then I use a change listener to set that value to the GameMap object. The GameMap object when changed fires a notification event to GameMapListeners, the primary listener it has is the preview display of the map inside the swing application.
This lets the user change the map width and instnatly see the results in a preview pane.
Now I want to go to the other way. I want the user to be able to click and drag the edges of the map in the preview pane, but then the results need to then be sent to the properties panel so it shows the updated width value.
This is where the problem is, if I update the jtextfield it'll fire a change event, which would update the GameMap and update the preview display, and then that would fire an event that changes the jtextfield again (so on and on until the program crashes due to stack overflow)
Are there any kind of design patterns i could use instead, or is there some common way to solve this issue?
In this type of case, you have at least two choices...
You Could
Remove the listener to the other component when you want to trigger a change, adding it back after you've raised the event...
You Could
Change the state of a flag to indicate that you should ignore any changes that might come in, resetting after you're raised the event...
Which one you choose will depend on how much code you want to add and how readily available the reference to the listeners in question are (ie, if you don't have a reference to the listener you want to remove, it's kind of hard to implement)
If I update the jtextfield it'll fire a change event, which would update the GameMap and update the preview display, and then that would fire an event that changes the jtextfield again (so on and on until the program crashes due to stack overflow).
When you have a situation like this, you can temporarily remove event listeners, fire the change event, and add the event listeners back. Yes, this is as much of a pain as it sounds, but it's a good way to prevent the stack overflow.
You can see a detailed explanation as well as a working example of managing event listeners in my Sudoku Solver Swing GUI article.
You can use action events for a JTextField. Action events don't trigger when you change the component programmatically.

Retaining Focus for KeyboardListener

I have a JFrame which contains most everything in the application. It has a KeyListener attached, and it also has several buttons and textfield on it. The problem it, when a button is clicked or a textfield is selected, it gets focus and shortcuts don't work. Of course, one can tab out of them, but to do this you must tab through EVERYTHING (each button, each textfield) before giving the window focus again.
Is there a sensible way to only require one tab to return focus to the frame from the textfield, and no tabs to return focus to the frame from a button click?
A WindowListener doesn't seem like the best way to do this, but if it's the only way I suppose I can forge forward there.
Thanks in advance!
It has a KeyboardListener attached
I have never heard of the KeyboardListener class so I can only guess what you are trying to do.
My guess is that you should NOT be using a listener of any kind.
Instead you should be using Key Bindings.
If you only need this for the textfield, you can add a keyListener to the textfield and when the user presses tab use yourJFrame.requestFocus(). Otherwise refer you may want to use a window manager or a key map.

How to avoid infinite update loops in Swing?

I have a JPanel with a set of items (for example combo boxes and text fields). Some action listeners are implemented on those items to register user updates.
If the user selects a value in a JComboBox (for example), the action listener captures the event. The corresponding underlying bean method is called and the panel is refreshed. Changing can have an impact on other fields displayed in the pane.
The problem is that when the panel is refreshed, all listeners are triggered, and they call for a refresh themselves. This leads to an infinite loop.
How can I avoid this? I can't get rid of the listeners, because I need to capture user updates, but I don't want these to fire when I am only refreshing the panel content.
One option is to have a central boolean value or some indicator that each listener can check to prevent the chaining of events.
Another option is to not refresh the field if the value does not change. That way each component is updated at most once per refresh.
I can't get rid of the listeners, because I need to capture user updates, but I don't want these to fire when I am only refreshing the pane content
Then remove the listeners, refresh the pane content and then restore the listeners. This way the listeners only fire when a user change is made.
I think that if your problem is in combobox it just points to a bug. Really, if user changes the value of the combobox, that somehow triggers refresh of the pane the value of the combo box should not be changed second time! So if it is onValueChanged() (or something like this) it should not be called at all when pane is being refreshed.
But if for some reason it happens you can verify whether the old and new values are the same and exit the listener.
If this still does not help I'd suggest you some non-standard solution: try to investigate the stack trace into the listener. Can you identify whether the listener was called as a direct reaction to user's action or after the pane refresh? In this case you can create utility method and put it in the beginning of all relevant listeners.
My applications also suffered from this problem, and solution with the flag, that I should check in every listener and enable/disable in code, feels not very good for me. I always forgot to set this flag to true/false in necessary places.
That is why I decide to implement another solution.
I just subclass all default swing components that I am using often, and implemented custom ValueChanged event that I fire after mouse/keyboard/clipboard/etc events. Now I am always know, that if ValueChanged event is fired, it means, that value was issued by user, not by code. Event handling in this way much more cleaner. This solution solves my problem.

Categories

Resources