Java Swing GUI hour glass - java

There is a JTabbedPane In my Swing program.
When user clicks on a tab, the program takes a while to get the data and process the results, then shows the results in the selected tab.
How can I display a hour glass, or something of that effect so that user knows it's processing data? Not to click on the tab again before it finishes it job.

The simplest way is to just call setCursor on the appropriate component (probably the top-level window) with the appropriate Cursor.
component.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
And then set it back when you are done.
component.setCursor(Cursor.getDefaultCursor());

A JProgressBar (possibly in indetermiante mode) sounds right - put that on the tab until the data has been fetched. A well-designed UI shouldn't force the user to wait for long-running tasks to complete and instead allow them to do something else inbetween.

setCursor(int) is deprecated. This is probably a bit cleaner:
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));

As the other answers mention, you can set a wait cursor, but you also mention preventing additional mouse clicks. You can use a glass pane to prevent clicks on components until the long operation is finished. In addition to the Sun tutorials on the glass pane, there is a nice example at http://www.java2s.com/Code/Java/Swing-JFC/DemonstrateuseofGlassPane.htm

I would as other mentioned
Change the cursor
Use a SwingWorker
Display the progressbar or an animated image in the glasspane
Hide the glasspane when the task is completed
Restore the default cursor

Related

Get left mouse button status without event

I need to scale my dialogs, when moving them to a different screen. Since scaling all components is quite expensive, I only want to do it once, when the dialog is moved to its new location.
So I used a timer, which restarts with every incoming componentMoved event, to know, when the dialog stops moving. This works great, as long as the mouse is released when stopping the dialog.
If the dialog stops moving and the mouse is still pressed, scaling works. But as soon, as I release the mouse, my L&F engine resizes the dialog to its previous size, which is very inconvenient.
I tried pack(), setting the size manually (I know, bad practice), I tried setVisible(false) before scaling and setVisible(true) afterwards, but as long as the mouse is pressed, my L&F engine resizes the dialog to its previous size.
Sadly, all MouseEvents concerning the titleBar are swallowed by the engine, so I cannot simply use a mouseReleased event to trigger scaling.
This is why I need to find out, if the mouse is still pressed without having to use an event. Is there any way? JNI somehow?
I cannot show an example, because without the L&F Engine, it works fine. Not using it is also not an option.
I think, you should use ComponentListener. When windows size is changed, your layout manager must trigger relayout and component sizes must be changed.
Also for debugging purposes you can use AWTEventListener to get all events which are thrown in your UI.
Toolkit.getDefaultToolkit().addAWTEventListener(...);
setting the size manually (I know, bad practice)
It's not a bad practice. Especially when you want to restore previous size of your window. pack() is simply preferred way.

swing focus issue, lost focus, focusgain not invoked

I have a complex and heavy swing client application which contains many modal compponents, jdialogs, internal frames etc. on some cases, a problem occurs and it is impossible to focus on swing textfields anymore. You may click on some jbuttons, jcheckboxes but it is impossible to focus and edit values on editable jtextfields anymore. The gainfocus events of editable textfields are not triggered anymore, only the requestfocus methods are invoked when you perform click on textfields.
I found a way(hack) so resolve the problematic case, when the trouble case occurs, and you show some joptionpane message or modal jdialog and close it by clicking or disposing, the problem goes away any you may click onto the textfields and edit them.
As a solution, i do some check, if you try focusing on a component, i start a timer thread in the requestfocus event of clicked textfield and keep the instance as focusrequesting component. After some time i check the last focused component by
KeyboardManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner()
If no problem occured, and the textfield gained the focus, the returned object (retur value of getPermanentFocusOwner) is the same instance as the focusrequesting component. But if the problematic case occured, the returned object is different from the focus requesting one and i open my temporarily jdialog by:
JDialog dialog=new OptionPane().createDialog(KeyboardFocusManager.getCurrentFocusManager().getActiveWindow(), "");
dialog.setModal(true);
// MUST be modal to fix the lost focus case
// start closing thread, which closes the dialog after some few time by dialog.dispose
new Closer(dialog).start();
dialog.setVisible(true);
This mechanism works, i now it is not very stable. And on some cases,the dialog.dispose() does not work, the temporarily windows remains always on the screen, not closeable, and because it is modal, client can not do any actions anymore. The dialog MUST be modal to solve the focus problem, because non-modal dialogs does not resolve the focus problem declared above. The dispose method of jdialog has many synchronized blocks, mutex objects etc, I think there occurs some deadlocks.
Any better mechanism suggestions, ideas? I know the best solution is to check the current application, analyse it or rewrite it. But it is very complex, heavy and model and view is not well properly organised. I have short time because the client is waiting, need some temporarily solutions, tricks or hacks.
You may click on some jbuttons, jcheckboxes but it is impossible to
focus and edit values on editable jtextfields anymore.
this is issue (quite common) with JTextField in JWindow without parent (JFrame), use undecorated JDialog instead
I saw here some issue with Focus, FocusSubsystem on Linux OS with last Java version, but never caused to block users input to JTextField
the best workaround for a.m. issue is RequestFocusListener by #camickr
dialog.setVisible(true); should be wrapped in invokeLater(), more see in Initial Thread (valid for all Top-Level Containers created on runtime too)
nothing clear from your question without posting an SSCCE, short, runnable, compilable, demonstraded, caused with a.m. issue

Globally disable all mouse input when a JDialog is showed

I would like to implement what follows:
when my application perform some critics operations or produce some errors, i want to display an alert JDialog telling the user what is happening.
Now, because some errors may put my application into an inconsistent status, until they are resolved, i would like temporarily disable mouse event dispatch to all components (including JMenu, JToolbar, .. )except the showed JDialog.
Is there anyway to do that? Or I have to manually removed all mouse listeners from all of components of my application, and re-add them later?
Make the dialog "modal" with setModal(true).
Simplest way is to call
frame.setEnabled(false);
where frame is your top-level window.
Note that the above soln may change the look of frame until its enabled again. For real control people play around with EventQueue's.

Help needed in diagnosing a painting issue on alt-tab in Swing

I have been looking into this for a few hours now and haven't found anything to guide my way. I have a Windows Swing GUI program that is performing some background processing in a SwingWorker. This also uses a progress dialog to let the user know how long the background processing will take.
The original designer of this system decided to disable mouse and keyboard input to the user interface, with the exception of the "Cancel" button on the progress dialog. They did this by using a glasspane that ignores all mouse and keyboard events.
The actual issue is that if the user alt-tabs or a screensaver happens, the user interface behind the glasspane never repaints. The progress dialog repaints, but this is due to the SwingWorker calling repaints periodically to update the progress.
I would like any advice for where to look to next. I haven't been able to find anything on alt-tab repainting in Java. Perhaps the progress dialog is modal by definition, preventing the EDT from repainting? Or perhaps the glasspane prevents repaints of "hidden" components?
Thanks,
Ryan
The article How to Write Window Listeners covers this topic. Using this example, you should see pairs of window events on each alt-tab event, similar to these:
java.awt.event.WindowEvent[WINDOW_LOST_FOCUS,opposite=null,oldState=0,newState=0] on One
java.awt.event.WindowEvent[WINDOW_DEACTIVATED,opposite=null,oldState=0,newState=0] on One
java.awt.event.WindowEvent[WINDOW_ACTIVATED,opposite=null,oldState=0,newState=0] on One
java.awt.event.WindowEvent[WINDOW_GAINED_FOCUS,opposite=null,oldState=0,newState=0] on One
If the glass pane's opaque is true, the repaint manager will not repaint the panel below. It's a performance optimization.

JScrollPane Scrolls Down with Long Text in JEditorPane

I want to have a JEditorPane inside a JScrollPane. When the user clicks a button, the click listener will create a textEditor, call jscrollpane.setViewPort(textEditor), call textEditor.setText(String) to fill it with editable text, and call jscrollpane.getVerticalScrollBar().setValue(0). In case you're wondering, yes, the setText() must come after the setViewPort() for reasons that aren't on topic.
Here is the problem: After the user clicks the button, the JScrollPane's view scrolls all the way to the bottom. I want the scrollbar to be at the top, as per the last line in my click listener.
I popped open a debugger, and to my horror, discovered that the jscrollpane's viewport is being forced down to the bottom after the conclusion of the click listener (when pumping filters). It appears that Swing is delaying the population of the editor/jscrollpane until after the conclusion of the clicklistener, but is calling the scrollbar command first. Thus, the undesired behavior.
Anyway, I'm wondering if there is a clean solution. It seems that wanting a scrollpane to be scrolled to the top after modification would be a reasonably common requirement, so I'm assuming this is a well-solved problem.
Thanks!
You could use JEditorPane.setCaretPosition(0).
Ok, it amazes me how I always figure out the answer fractions of a second after posting.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
pane.getVerticalScrollBar().setValue(0);
}
});
This allows the scrolling action to be delayed until after the other task completes. Question: is this good style/reliable or is it just a race condition? Can I depend on this working?

Categories