What I am trying to do is have a small splash screen appear while my program is loading something. This is what I have:
SplashScreen.showSplashScreen();
// Do stuff that takes time.
SplashScreen.hideSplashScreen();
All the showSplashScreen() method does is create a new JWindow in the middle of the screen and make it visible.
Now this code is called from the event dispatching thread, so when the showSplashScreen() method is called, I don't get to see the JWindow until the thread has finished, which by then, I don't need the window anymore. What would be the best way to go about showing this splash screen while I was waiting?
Not sure if this is the "best way", but a mechanism I've used before is to do your initialisation on a thread other than the EDT, but show your splash screen using SwingUtilities.invokeAndWait. That way, you'll at least get to see the splash screen even if your initialisation is quick (if that's what you want to happen).
So on your init thread, you go:
SwingUtilities.invokeAndWait( /* Runnable to show splash screen */ );
// Do stuff that takes time.
SwingUtilities.invokeLater( /* Hide splash screen, display main GUI */ );
There is a java.awt.SplashScreen class that was introduced in 1.6, tried using that?
Related
I want to do the following:
I've got a LWJGL display, and a running game loop. I did not explicitly create a thread for this. It just runs on the thread it takes. (the thread it is created in?)
Now I want to create a Swing JFrame, but of course this is not that simple.
Because when I tried this, the swing window blocks. It just doesn't update and it won't close, and this behaviour is expected.
I tried to create a new thread and put the JFrame in that new thread, but also this doesn't change the behavior.
I really know swing should be executed in the Event Dispatch Thread, but I don't know how to solve this problem. I also tried a lot with SwingUtils.invokeLater, but actually this has very little to do with the problem.
What can I do to have a LWJGL display and a working JFrame at the same time?
I want that JFrame to display generated BufferedImages to debug. The BufferedImages are used for creating textures. I don't want to output that debugging data to disk, and just want to display the images in a JFrame.
I have JFrame, that is setUndecorated(true) and inside it's content pane there is a LwjglCanvas a libgdx application rendering it's things.
I need at some point, do setUndecorated(false). But is seems to be impossible.
the decorated state cannot be changed once JFrame has been displayed, the only way to do it is to either create new JFrame, or dispose the existing one, and pack it back. Both solutions are terrible for me, because both will eventually notify LwjglCanvas to stop, and once stopped it cannot be started again.
I tried overwriting it's stop method, but it still get's messed up somehow.
Why do I need this?
I am trying to make a loading splash screen for libGDX desktop app, with a progress bar in it, that should display progress of my desktop app loading it's resources in opengl context. Splash screen has to be undecorated window, and when all loaded app itself should show, maximized and decorated.
Approaches that do not work:
Use one JFrame, and switch between decorated modes.
Try to move Lwjgl canvas from one JFrame to another
Use 2 separate Lwjgl canvases (cannot be done, because only one Al
context can be inited at a time)
How do I do this?
Context: in my Java Swing app I have a chart (using JFreeChart) and when the user clicks on a datapoint on it, it opens a specific flash animation in a JDialog (flash played using DJNativeSwing).
Problem: when the flash animation starts playing, for some reason the background chart in the main window decides to refresh (calls its paintComponent()) and, as the chart is fairly heavy, this takes ~4 seconds during which the flash animation freezes.
I am thus looking for the most elegant / simplest solution to avoid the flash freeze. So far, I could imagine:
Find out why paintComponent() is called and avoid this
Open the JDialog (or child window without modal behavior) on a different thread
What would be the best approach and, most importantly, how to do it?
How to stop movements of my JFrame on screen/Monitor?
My JFrame size is as much as Screen/Monitor size and my client does not even want to display the task bar.
If I write myFrame.setExtendedState(JFrame.MAXIMIZED_BOTH),
it is not allowing to move on screen but showing taskbar, but I don't want to display taskbar.
You actually want so called "full-screen mode". Take a look on this article to see how to do this: http://docs.oracle.com/javase/tutorial/extra/fullscreen/exclusivemode.html
Shortly you have to call device.setFullScreenWindow(myWindow)
(In my applicaton with Swing GUI) I want to display GlassPane during some work performed in a loop or method, which is called after clicking JButton.
For example:
(action performed after clicking a button)
if (item.equals(button)) {
glassPane.setVisible(true);
someTimeConsumingMethod();
glassPane.setVisible(false);
}
Running this code results in not showing the glassPane during execution of someTimeConsumingMethod() - GUI just freezes for a moment, before result is displayed. Removing last line in that loop (glassPane.setVisible(false);) results in showing glassPane after the method is done (when GUI unfreezes).
Is there a simple way to show that glassPane before GUI freezes, or I need to use some advanced knowledge here? (threads?)
UPDATE1:
I've updated my code according to davidXYZ answer (with two changes):
(action performed after clicking a button)
if (item.equals(button)) {
glassPane.setVisible(true);
new Thread(new Runnable(){
public void run(){
someTimeConsumingMethod(); // 1st change: running the someTimeConsumingMethod in new Thread
// instead of setting glassPane to visible
}
}).start();
// 2nd change: moved glassPane.setVisible(false); inside the someTimeConsumingMethod(); (placed at the end of it).
}
The point of 1st change is that setting glassPane visible in new thread right before running someTimeConsumingMethod in my GUI thread was revealing the glassPane after someTimeConsumingMethod finished (double-checked this).
Now it works fine, thank you for all answers. I will definitely check all the links you provided to actually understand threads!
UPDATE2:
Some more info: someTimeConsumingMethod(); in my application is prepering new Swing Components accoriding to the XML data (cards builded from JButtons and JLabels with few JPanels where needed, and adding them in correct places).
UPDATE3:
I am trying to make it work using SwingWorker's invokeLater method. Now it looks like that:
(action performed after clicking a button)
if (item.equals(button)) {
glassPane.setVisible(true);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
someTimeConsumingMethod();
glassPane.setVisible(false);
}
});
}
It works not that good as code from UPDATE1 (but still - it works). Problems are:
glassPane loads without .gif animation (file is setted up in custom glassPane class - it works with UPDATE1 code)
there is small delay at the end of "working" process - first cursor changes to normal (from the WAIT_CURSOR), and after very short moment glassPane disappear.
Cursor is changed by the custom glassPane class on activation/deactivation (no delay using new Thread way).
Is it correct way of using SwingWorker's invokeLater method?
EDIT: My mistake, I confused SwingWorker with SwingUtilities.invokeLater(). I guess the image issue is due to GUI freezing when the someTimeCOnsumingMethod starts.
GUI just freezes for a moment, before result is displayed. Removing last line in that loop (glassPane.setVisible(false);) results in showing glassPane after the method is done (when GUI unfreezes).
this is common issue about Event Dispath Thread, when all events in EDT are flushed to the Swing GUI in one moment, then everything in the method if (item.equals(button)) { could be done on one moment,
but your description talking you have got issue with Concurency in Swing, some of code blocking EDT, this is small delay, for example Thread.sleep(int) can caused this issue, don't do that, or redirect code block to the Backgroung taks
Is there a simple way to show that glassPane before GUI freezes, or I need to use some advanced knowledge here? (threads?)
this question is booking example why SwingWorker is there, or easier way is Runnable#Thread
methods implemented in SwingWorker quite guarante that output will be done on EDT
any output from Runnable#Thread to the Swing GUI should be wrapped in invokeLater()
easiest steps from Jbuttons Action could be
show GlassPane
start background task from SwingWorker (be sure that listening by PropertyChangeListener) or invoke Runnable#Thread
in this moment ActionListener executions is done rest of code is redirected to the Backgroung taks
if task ended, then to hide GlassPane
create simple void by wrapping setVisible into invokeLater() for Runnable#Thread
in the case that you use SwingWorker then you can to hide the GlassPane on proper event from PropertyChangeListener or you can to use any (separate) void for hidding the GlassPane
best code for GlassPane by #camickr, or my question about based on this code
You are blocking the EDT (Event Dispatching Thread, the single thread where all UI events are handled) with your time consuming job.
2 solutions:
Wrap the calls to:someTimeConsumingMethod();glassPane.setVisible(false); in SwingUtilities.invokeLater(), this will allow the frame to repaint itself once more. However this will still freeze your GUI.
Move your someTimeConsumingMethod() into a SwingWorker (this is the recommended option). This will prevent your GUI from ever freezing.
Read the javadoc of SwingWorker to understand better what is going on and how to use it.
You may also learn a lot in this tutorial about Swing and multi-threading
JButton startB = new JButton("Start the big operation!");
startB.addActionListener(new ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent A) {
// manually control the 1.2/1.3 bug work-around
glass.setNeedToRedispatch(false);
glass.setVisible(true);
startTimer();
}
});
glasspane here used here is FixedGlassPane glass;
ref: http://www.java2s.com/Code/Java/Swing-JFC/Showhowaglasspanecanbeusedtoblockmouseandkeyevents.htm
Guillaume is right. When you are on the main thread, each line will finish before the next line. You definitely need another thread.
An easy way to solve your problem is to spin off the display of the glasspane in another thread (normal thread or Swing threads - either will work fine).
if (item.equals(button)) {
new Thread(new Runnable(){
public void run(){
glassPane.setVisible(true);
}
}).start();
someTimeConsumingMethod();
glassPane.setVisible(false);
}
That way, a different thread is blocked by setvisible(true) while someTimeConsumingMethod() runs on the main thread. When it's done, glasspane will disappear. The anonymous thread reaches the end of the run method and stops.