Drawing animations at the show of a JDialog - java

What would be the best way to draw a simple animation just before showing a modal JDialog? (i.e. expanding borders from the mouse click point to the dialog location). I thought it would be possible to draw on the glasspane of the parent frame on the setVisible method of the dialog.
However, since the JDialog is modal to the parent, I couldn't find a way to pump drawing events into EDT before the JDialog becomes visible, since the current event on the EDT has not been completed yet.

Are you trying to show the JDialog indepentently of the annimation? In order to get the order set properly, you may need to bundle those actions in a runnable that is passed to the EDT at once.
eg:
SwingUtilities.invokeLater(new Runnable(){
public void run(){
doAnnimation();
showDialog();
}
}
It may be best to subclass JDialog so that you can just add the doAnnimation() logic to the setVisible(..) or show() method before calling the superclass implementation.
Finally, I imagine you'll need to set the dimensions of the dalog manually -- I don't remember if Java will know the actual size of the dialog before it is shown, so you may get some useless information for your annimation if you query the size before showing it.

Maybe you have a look at the SwingWorker Project which is included in JSE 6. (Link to SwingWorker) In the book "Filthy Rich Client" that I am reading at the moment they use this tool a lot. Maybe you can find a hint in the examples on the books website: http://filthyrichclients.org/

You may be able to take #rcreswick's answer and expand on it a little to make it work.
void myShowDialog() {
new Thread(new Runnable() {public void run() {
SwingUtilities.invokeAndWait(new Runnable() { public void run() {
doAnimation();
} } );
// Delay to wait for the animation to finish (if needed)
Thread.sleep(500);
SwingUtilities.invokeAndWait(new Runnable() { public void run() {
showDialog();
} } );
} } ).start();
}
It's pretty ugly and would have to be invoked in place of the basic showDialog() call, but it should work.

One possibility is to paint your own dialog on the Glass Pane. Then you have full control of the dialog and can paint whatever you want. Here's a tutorial on creating animations on the Glass Pane.

Related

Keep focus on a JDialog using SwingUtilities.invokeLater?

I want to display a JDialog so I use this:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() { new DialogBox().setVisible(true); }
});
It works fine to display it but then my JDialog doesn't keep the focus, which it needs to (the user should not be able to work using the main UI while that dialog is open).
Is it safe to get rid of the SwingUtilities.invokeLater()?
Oh and according to this question it is not wise to extend JDialog or JFrame, why? That's how I've always done it.
It works fine to display it but then my JDialog doesn't keep the
focus, which it needs to (the user should not be able to work using
the main UI while that dialog is open).
have to setModal(true) or setModalityTypes(various types) for parent, or all windows from current JVM
Is it safe to get rid of the SwingUtilities.invokeLater()
yes exactly, all Top-Level Container should be created on EDT, wrapped in invokeLater(), including JOptionPane

Applet flickers with no image present

Im currently building an applet and ran into an updating/repainting problem. I have string drawn that updates the coordinates of the mouse. The problem starts when I move the mouse. The coordinates update (by means of repaint() within the mouseMoved() method, but the applet flickers until I stop moving.
I've tried looking for solutions, but they only deal with if there was an image present. My applet only contains buttons, text (drawString()) and a gradient background. When it flickers, everything but the buttons flickers. Is there an alternative to stop the flickering when dealing with an applet that DOESNT use image files?
In Java Swing there is a concept of Event Dispatch Thread (EDT):
You can try putting in your Applet.init() method
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
and to perform all related GUI stuff only in EDT.

Showing GlassPane before entering loop

(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.

Why setVisible doesn't work?

I have a swing GUI with border layout. in the NORTH I have added some component.
My label component which has GIF icon is invisible lblBusy.setVisible(false);
later a button make it visible like below. Why it does not show up?
btnDownload.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
lblBusy.setVisible(true);
btnCancel.setEnabled(true);
}
});
download = new Download(txtSource.getText(), new File(txtDestination.getText()), textAreaStatus);
download.start();
lblBusy.setVisible(false);
}
});
1) this is EventDispatchThread rellated issue, EDT quite guaranteed that all changes to the GUI would be done on one moment
2) you invoked ActionPerformed from JButton, and untill all events ended your GUI should be freeze or is unresponsible, same for JButton and JLabel in your case
3) better would be redirect reading for File contents to the Backgroung task e.g. SwingWorker or Runnable#Thread then JButton and JLabel will be changed and GUI would be during Background task responsible for Mouse or KeyBoard
or
4) dirty hack split to the two separated Action delayed by javax.swing.Timer, but in this case again untill all events ended your GUI will be freeze or is unresponsible
Most probably because the GUI was packed at a time the label was not visible, so no space was assigned to display it. For anything more definite, post an SSCCE.
It seems to me that you are writing lblBusy.setVisible(true); and after that lblBusy.setVisible(false); in the mouseClicked() method. Since you wanted to make it visible at the click of a button aren't you be using only lblBusy.setVisible(true);, instead of using both.
You can call lblBusy.setVisible(false); from the end of your Download Class though, once it's done doing what it does.
Regards

JWindow alway on top not getting focus events

I have a jwindow(set to be always on top) that you can click to get a pop menu. If the user right clicks the window it shows the pop menu but then if the user clicks any other window(such as firefox) pop menu does not disappear.
I tried to fix it by adding FocusListener on the jwindow, i implemented FocusListener and override
public void focusGained(FocusEvent e) {
System.out.println("gain" );
}
public void focusLost(FocusEvent e) {
System.out.println("lost" );
}
but there event never get called. i also tried the following,
addWindowFocusListener(new WindowAdapter() {
public void windowGainedFocus(WindowEvent e) {
System.out.println("gain 2" );
}
});
this event also not called.
All this jwindows has is a single JLabel with a picture on it.
From memory JWindow's do not receive focus/window events.
You are suppose to call setFocusableWindowState(true) on a JWindow to allow it to be focusable. But that "still" is not enough. The JWindow must also have focusable Components and I'm still not able to get it to work.
Using JFrame setUndecorated() seems the best choice.
To be focusable, a JWindow needs to be created with a parent Frame, like new JWindow(parentFrame). Do that and I think you should find it will automatically get the focus when you set it to visible.
Not really sure what you are trying to do. If you are trying to hide the popup manually then you should probably use a WindowListener and handle the windowDeactivated event.
If you really want to display a popup menu, you should be using JPopupMenu, not implementing it yourself.

Categories