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.
Related
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.
Is there anyway that I can control the order in which events are fired in my Swing application?
For example, I have a MouseListener and an ActionListener for a component. Can I make it so the MouseListener always fires before the ActionListener?
Seems to me if I add the MouseListener before the ActionListner, I am just praying that they will fire in that order.
Now I understand that coding this way is bad practice and that you should not count on the order of events firing, but for this situation I am encountering, it is a must.
Thanks
If you have an action triggered off of a one listener that needs to happen before the other then change your logic.
Either combine the listeners so that a single listener gets both events and holds onto one temporarily if needed. Or only add one listener and have it call the appropriate method or create a new event after it finishes.
Wrap the ActionListener code in a SwingUtilities.invokeLater(...). The code will be added to the end of the EDT.
I would still have both listeners in the same class so the dependency is well documented.
As most Java programmers know, updates to Swing GUIs should only be done on the AWT event dispatching thread and the recommendation is that long-running processes be executed on a "worker" thread, with updates sent to the event dispatching thread using SwingUtilities.invokeAndWait() or SwingUtilities.invokeLater().
How do you stop the user from proceeding with the application while the long-running process is completed? Do you gray out the controls and then have the worker thread reenable them using the SwingUtilities calls mentioned above?
Is there a better alternative pattern?
I would consider 3 solutions :
disable the components of the panel : it's generally what I do. Unfortunately, Swing does not provide a simple way to disable a panel and all its children, but it is easy to do the recursion (see this other SO answer for that). Another problem is that some Swing components look the same when enabled and disabled (JList, for example)
hide the panel with a CardLayout : in a panel with a CardLayout, add 2 components. The first is the panel that hosts the components to inactivate, and the second is a panel showing a "loading" or "please wait" message. A simple JLabel in a Gridbaglayout does the trick. Then, you just have to switch from one to another. I use this technique for places where a result of a computation/request is to be displayed.
put some kind of component on top of the panel that consumes the mouse events : you can do it yourself with a LayeredPane, or you can use a dedicated utility. JXLayer can do that (I read that JXLayer will be included in Java 7, so this may become the 'standard' solution to this kind of problem).
There are several ways and the selection of which, mostly depends on the design and layout of your GUI.
Use a Progress Bar - Replace the panel or an area that you don't want a user touching with a progress bar. This will prevent you from having to deal with events you don't want yet, while still making it clear to the user that something is happening in the background.
Disable buttons and add a Wait Cursor - Use setEnable(false) while work is being done and nd possibly change the cursor to a Wait Cursor. This again makes it clear that an option is not available yet only for a temporary period.
Don't respond to events or throw up a GlassPane - This is less user-friend as it makes the application look unresponsive, however it can acceptable in some situations.
One way I have seen it done is to use Jframe.setGlassPane() and set a component that eats all events. You can also be creative and use flash kind of rotating-wait gif in your glasspane. But note that setting a glass pane may not be all you want. For more advanced requirements, you may have to play around with event-queues.
in my application i get a component to focus ,
it could be a jpanel , and is could be a jbutton or a user custom made component
how can i know when to call transferFosus ,and when to call requestFocus
thanks you
transferFocus() sends focus to the next component. Also note that
transferFocus() will always transfer the focus in the forward direction.
requestFocus() sends focus to calling component. However, there is no guarantee that this will be successful. Focus behavior is platform-dependent to certain extend.
The recommended mentod for gaining focus is to use requestFocusInWindow(). Refer to this post - might come very handy in playing with focus.
Use transferFocus() when you want to advance focus according to the focus order.
requestFocus() is used to explicitly set the focus to a component.
Some background reading in Focus on Swing
It's rare that you would need to call either since its usually appropriate to let the user's keyboard/mouse actions determine focus. But transferFocus send focus away from your component and requestFocus brings focus to your component.
What is the best way to implement a global default context menu for a Swing app that has the Windows-standard cut/copy/paste/etc. popup menu for things like JTextField? Tim Boudreau suggested installing a custom UI delegate in this javalobby thread but that was written with Java 5 in mind, so I'm wondering if there's a better way today.
Are there plans to add this behavior in a future version of Swing itself?
Good timing. My blog entry for tomorrow was going to be about using Global Event Listeners. The simple answer is to use an AWTEventListener (instead of a custom EventQueue) to listen for MouseEvents and to then check the mouse event to see if it is a popup trigger.
I'll post the link to the entry tomorrow afternoon (EDT) when I get it published.
Then you can decide which approach is better.
You can now check out the Global Event Listeners entry for a really simple example of using an AWTEventListener.