I'm new to Java, I'm coding on NetBeans. The problem is that whenever I disable a control
i.e jmenu.setEnabled(false) it still fires events! holy crap! how is it! :P
How can I prevent it?
From the javadoc:
Note: Disabling a lightweight
component does not prevent it from
receiving MouseEvents.
Note: Disabling a heavyweight
container prevents all components in
this container from receiving any
input events. But disabling a
lightweight container affects only
this container.
You might want to check out disableEvents(long mask).
To fit in with the event model adopted by Swing, I think your best option is to just add a check of isEnabled() in the handlers that you don't want executed when the component is disabled.
Consider using javax.swing.Action-controlled Swing components.
In this way, you can instead disable an Action directly with Action.setEnabled. Its component(s) will adopt its state automatically. When disabled in this manner, the components won't receive MouseEvents.
See the docs on the constructor JButton(Action).
Related
I'm developing a plugin for IntelliJ IDEA, which obviously uses Swing.
For a feature I have introduced I'd like to stop a JPopupMenu which uses JCheckBoxMenuItems from losing focus and closing.
You can see it in action.
I've debugged the code, but I couldn't figure out how to do it, also being I'm not that into Swing.
Could you maybe point me to useful listeners/blocks of code/ways to prevent this?
If you want to see code, the IntelliJ classes are
ActionPopupMenuImpl.MyMenu
ActionMenuItem
Edit: a better way need to be found as the uiRefreshed event isn't always called at the right time.
Just coordinate your code in a good way ;)
The Swing mechanism in IDEA is too complicated, and maybe it's better to not touch it. Just know that the mouse events are handled by a special listener and then redirected to Component(s).
That said, having an hold on the menu ActionButton. You can listen for the Lookup's uiRefreshed event and programmatically:
myMenuButton.click()
That's all.
You need to call it after the UI has been refreshed because the LookupUi might have changed in dimension or location.
I have made a Pong clone, and I've come across a problem. The KeyListener only works sometimes. There is no pattern that I have been able to find.
For reference here is my Pong.java(the main class): http://pastebin.com/8d7BqK4x
Here is the Board.java(Graphics and KeyListener): http://pastebin.com/0zb526BE
KeyEvents are only generated when a component has focus.
A better approach is to use Key Bindings which work even when the component doesn't have focus.
Usually you don't want to use a KeyListener due to focus issues (which is likely why your listener only listens at times -- likely your listen-to component loses focus and so the KeyListener loses its function.
Better to use Key Bindings where you don't have to worry so much about focus issues and where you're dealing with a higher level construct, one that Swing uses itself to listen to components. The tutorials will "show you the way".
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.