Swing: How to prohibit interaction outside of JFrame/JDialog? - java

I'd like to show a progressbar and block interaction with my application frame while a thread is being executed.
In another thread someone suggested using JDialog instead of JFrame and setModal(true). However, when doing so the Dialog blocks the entire application.
This is essentially my code:
MyDialog dlg = new MyDialog();
dlg.setModal(true);
dlg.setVisible(true);
//do some stuff....
//(never executed when setModal(true)
dlg.setVisible(false);

The easiest way to do it would be using JXLayer and LockableUI.
Look here for an example of how this can be done.
Also note, that JXLayer made it into Java 7, and is available as javax.swing.JLayer.
The other thing is, that you should not execute long-running tasks insite Event Dispatch Thread. Read about SwingWorker and learn to write multithreaded code for Swing.

That is the point of a modal dialog, no interaction will happen outside the "box". The modal popup also halts the thread while waiting for user input. If you want to do other stuff while showing the dialog you will either have to do it in the dialog itself or start a new thread to take care of it.
Hope that helps!

With modal dialog try something like this:
final JDialog dlg = new JDialog();
dlg.setModal(true);
dlg.setSize(500, 500);
dlg.addWindowListener(new WindowAdapter() {
#Override
public void windowActivated(WindowEvent e) { //or other method
new Thread(new Runnable() {
public void run() {
try {
//execute your long running task
} //you should catch exception
finally {
dlg.setVisible(false);
dlg.dispose();
}
}
}).start();
}
});
dlg.setVisible(true);
I can also set GlassPane on your JFrame which will intercept any event from the user.

Related

How can I update JFrame objects during WindowClosing event?

I have a few shutdown steps which need to execute during a WindowClosing event before being disposed. Everything is executing correctly, but I'd like to add the capability to provide shutdown status messages in an existing JLabel within the closing JFrame. Is it possible to update the JLabel text during a WindowClosing event?
Sure. Just make sure component is not disposed before you start interacting with it.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// update label here
}
});
but I'd like to add the capability to provide shutdown status messages in an existing JLabel within the closing JFrame
label.setText(....);
label.paintImmediately(label.getBounds());
The code in the listener executes on the Event Dispatch Thread so the GUI can't repaint itself until all the listener code is executed and by that time the GUI will be closed.
The paintImmediately(...) will allow the component to bypass the RepaintManager and paint itself right away.
I used the following code to execute the shutdown steps in the background and then close the JFrame.
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
#Override
public Void doInBackground() {
// shutdown steps go here and can update the JLabel text
frame.dispose();
return null;
}
};
worker.execute();
}
});

Change a JLabel Text while an JButton listener is working

I have a JButton, lets call it "button" and added an ActionListener to it:
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
call();
}
});
It is correctly added to my frame etc. In that JFrame I also have a JLabel, and I want to change its text while the JButton method is working(because it takes ~30 secs to finish). How do I do that? Do I have to use some multi-thread-thingy?
Here is the basic principle(the JLabel is called output):
public void call(){
output.setText("test1");
try { Thread.sleep(1000);
} catch (InterruptedException e) {}
output.setText("test2");
}
This will result in the "output" Label being changed to "test2" after one second. How can I make it instantly display "test1"?
Don't use Thread.sleep(). This will prevent the GUI from repainting itself.
Do I have to use some multi-thread-thingy?
Yes.
For a long running task you need to start a separate Thread, so the GUI can remain responsive.
In this case you can use a SwingWorker.
Read the section from the Swing tutorial on Concurrency for more information and an example of using a SwingWorker.

Make JFrame GUI wait and then continue after a button is pressed

I have a gui class MyGUIClass that extends JFrame. I would like to accomplish following in java. I looked into EventQueue, but somehow could not get things right. I am not even sure if this is the correct approach.
In the main, I would like following sequence of events:
-> start JFrame
-> Keep JFrame active and wait until play button is pressed. when button pressed,
-> execute rest of the code in main, but keep gui alive to receive commands from JFrame.
try {
java.awt.EventQueue.invokeAndWait(new Runnable() {
public void run() {
new MyGUIClass().setVisible(true);
}
});
}
catch (Exception e) {
e.printStackTrace();
}
System.out.println("Portion to execute only after request from GUI");
}
But the above trial is not working and the println prints while gui is running without any commend from GUI.
You will have to provide a listener to the button on click of which you want to execute some code.
But if you want to put the code which you want to execute in main. You will need some anonymous class containing code or lambda etc.
I will show here how you can achieve what you want
class MyGUIClass extends JFrame {
...
// I am using Runnable to contain code you want to execute.
// You can use Function or any class/interface you want
Runnable codeToExecute;
MyGUIClass(Runnable codeToExecute){
this.codeToExecute = codeToExecute;
...
}
...
void yourGUImethod(){
...
JButton btn = new JButton(new AbstractAction(){
#Override
public void actionPerformed(ActionEvent e) {
codeToExecute.run(); // execute code on button press
}
});
yourPanel.add(btn); // Add this button to your panel
...
}
Now you can provide executing code from main
Runnable codeToExecute = () -> { // Using lambda
System.out.println("Portion to execute only after request from GUI");
}
java.awt.EventQueue.invokeAndWait(new Runnable() {
public void run() {
new MyGUIClass(codeToExecute).setVisible(true);
}
});
I am not even sure if this is the correct approach.
Well you haven't stated if this is the main window or a child window.
If this is a "child window" and you are prompting for information from the main window, then you should be using a modal JDialog for the child window.
If this is the "main window" then no it isn't the correct approach.
GUI's are event driven. This means you write code to respond to events.
So, when the frame is created you create all the components and add them to the frame.
For the "Play" button you need to add an ActionListener to the button. So when the button is pressed you invoke the code related to the play action.
Then the GUI will just sit there waiting for more events to be generated by the user.

Show ProgressBar with windowClosing(WindowEvent we)

I have a JFrame. Frame was executed on EDT. A window closing event is being added to that frame using window adapter. What i need is; There is a background task that delete files generated by the application; and that task starts running when the close button of frame is being clicked. I want to show progressbar for that background tasks?
public class CloseApplication extends WindowAdapter{
#Override
public void windowClosing(WindowEvent we) {
new Thread(new Runnable() {
#Override
public void run() {
delete.deleteDirectory(a);
delete.deleteDirectory(b);
delete.deleteDirectory(c);
delete.deleteDirectory(d);
}
}).start();
}
}
I tried to add progress bar to the process but it didn't displayed. I then called it in new thread; still no success. Can you give me any idea that how this can be done?
Either way i use to call it in new thread it dont work. The reason is; background task executes in new thread and windowClosing comes to an end and close the application. If i call it without it; it makes the UI unresponsive.
Thanks in advance.

How to programmatically close a JFrame

What's the correct way to get a JFrame to close, the same as if the user had hit the X close button, or pressed Alt+F4 (on Windows)?
I have my default close operation set the way I want, via:
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
It does exactly what I want with the aforementioned controls. This question isn't about that.
What I really want to do is cause the GUI to behave in the same way as a press of X close button would cause it to behave.
Suppose I were to extend WindowAdaptor and then add an instance of my adaptor as a listener via addWindowListener(). I would like to see the same sequence of calls through windowDeactivated(), windowClosing(), and windowClosed() as would occur with the X close button. Not so much tearing up the window as telling it to tear itself up, so to speak.
If you want the GUI to behave as if you clicked the X close button then you need to dispatch a window closing event to the Window. The ExitAction from Closing An Application allows you to add this functionality to a menu item or any component that uses Actions easily.
frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));
setVisible(false); //you can't see me!
dispose(); //Destroy the JFrame object
Not too tricky.
If by Alt-F4 or X you mean "Exit the Application Immediately Without Regard for What Other Windows or Threads are Running", then System.exit(...) will do exactly what you want in a very abrupt, brute-force, and possibly problematic fashion.
If by Alt-F4 or X you mean hide the window, then frame.setVisible(false) is how you "close" the window. The window will continue to consume resources/memory but can be made visible again very quickly.
If by Alt-F4 or X you mean hide the window and dispose of any resources it is consuming, then frame.dispose() is how you "close" the window. If the frame was the last visible window and there are no other non-daemon threads running, the program will exit. If you show the window again, it will have to reinitialize all of the native resources again (graphics buffer, window handles, etc).
dispose() might be closest to the behavior that you really want. If your app has multiple windows open, do you want Alt-F4 or X to quit the app or just close the active window?
The Java Swing Tutorial on Window Listeners may help clarify things for you.
Stop the program:
System.exit(0);
Close the window:
frame.dispose();
Hide the window:
frame.setVisible(false);
If you have done this to make sure the user can't close the window:
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
Then you should change your pullThePlug() method to be
public void pullThePlug() {
// this will make sure WindowListener.windowClosing() et al. will be called.
WindowEvent wev = new WindowEvent(this, WindowEvent.WINDOW_CLOSING);
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(wev);
// this will hide and dispose the frame, so that the application quits by
// itself if there is nothing else around.
setVisible(false);
dispose();
// if you have other similar frames around, you should dispose them, too.
// finally, call this to really exit.
// i/o libraries such as WiiRemoteJ need this.
// also, this is what swing does for JFrame.EXIT_ON_CLOSE
System.exit(0);
}
I found this to be the only way that plays nice with the WindowListener and JFrame.DO_NOTHING_ON_CLOSE.
Exiting from Java running process is very easy, basically you need to do just two simple things:
Call java method System.exit(...) at at application's quit point.
For example, if your application is frame based, you can add listener WindowAdapter and and call System.exit(...) inside its method windowClosing(WindowEvent e).
Note: you must call System.exit(...) otherwise your program is error involved.
Avoiding unexpected java exceptions to make sure the exit method can be called always.
If you add System.exit(...) at right point, but It does not mean that the method can be called always, because unexpected java exceptions may prevent the method from been called.
This is strongly related to your programming skills.
** Following is a simplest sample (JFrame based) which shows you how to call exit method
import java.awt.event.*;
import javax.swing.*;
public class ExitApp extends JFrame
{
public ExitApp()
{
addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
dispose();
System.exit(0); //calling the method is a must
}
});
}
public static void main(String[] args)
{
ExitApp app=new ExitApp();
app.setBounds(133,100,532,400);
app.setVisible(true);
}
}
Not only to close the JFrame but also to trigger WindowListener events, try this:
myFrame.dispatchEvent(new WindowEvent(myFrame, WindowEvent.WINDOW_CLOSING));
Best way to close a Swing frame programmatically is to make it behave like it would when the "X" button is pressed. To do that you will need to implement WindowAdapter that suits your needs and set frame's default close operation to do nothing (DO_NOTHING_ON_CLOSE).
Initialize your frame like this:
private WindowAdapter windowAdapter = null;
private void initFrame() {
this.windowAdapter = new WindowAdapter() {
// WINDOW_CLOSING event handler
#Override
public void windowClosing(WindowEvent e) {
super.windowClosing(e);
// You can still stop closing if you want to
int res = JOptionPane.showConfirmDialog(ClosableFrame.this, "Are you sure you want to close?", "Close?", JOptionPane.YES_NO_OPTION);
if ( res == 0 ) {
// dispose method issues the WINDOW_CLOSED event
ClosableFrame.this.dispose();
}
}
// WINDOW_CLOSED event handler
#Override
public void windowClosed(WindowEvent e) {
super.windowClosed(e);
// Close application if you want to with System.exit(0)
// but don't forget to dispose of all resources
// like child frames, threads, ...
// System.exit(0);
}
};
// when you press "X" the WINDOW_CLOSING event is called but that is it
// nothing else happens
this.setDefaultCloseOperation(ClosableFrame.DO_NOTHING_ON_CLOSE);
// don't forget this
this.addWindowListener(this.windowAdapter);
}
You can close the frame programmatically by sending it the WINDOW_CLOSING event, like this:
WindowEvent closingEvent = new WindowEvent(targetFrame, WindowEvent.WINDOW_CLOSING);
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(closingEvent);
This will close the frame like the "X" button was pressed.
If you really do not want your application to terminate when a JFrame is closed then,
use : setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
instead of : setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Here's a synopsis of what the solution looks like,
myFrame.dispatchEvent(new WindowEvent(myFrame, WindowEvent.WINDOW_CLOSING));
This examples shows how to realize the confirmed window close operation.
The window has a Window adapter which switches the default close operation to EXIT_ON_CLOSEor DO_NOTHING_ON_CLOSE dependent on your answer in the OptionDialog.
The method closeWindow of the ConfirmedCloseWindow fires a close window event and can be used anywhere i.e. as an action of an menu item
public class WindowConfirmedCloseAdapter extends WindowAdapter {
public void windowClosing(WindowEvent e) {
Object options[] = {"Yes", "No"};
int close = JOptionPane.showOptionDialog(e.getComponent(),
"Really want to close this application?\n", "Attention",
JOptionPane.YES_NO_OPTION,
JOptionPane.INFORMATION_MESSAGE,
null,
options,
null);
if(close == JOptionPane.YES_OPTION) {
((JFrame)e.getSource()).setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE);
} else {
((JFrame)e.getSource()).setDefaultCloseOperation(
JFrame.DO_NOTHING_ON_CLOSE);
}
}
}
public class ConfirmedCloseWindow extends JFrame {
public ConfirmedCloseWindow() {
addWindowListener(new WindowConfirmedCloseAdapter());
}
private void closeWindow() {
processWindowEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
}
}
Based on the answers already provided here, this is the way I implemented it:
JFrame frame= new JFrame()
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// frame stuffs here ...
frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));
The JFrame gets the event to close and upon closing, exits.
You have to insert the call into the AWT message queue so all the timing happens correctly, otherwise it will not dispatch the correct event sequence, especially in a multi-threaded program. When this is done you may handle the resulting event sequence exactly as you would if the user has clicked on the [x] button for an OS suppled decorated JFrame.
public void closeWindow()
{
if(awtWindow_ != null) {
EventQueue.invokeLater(new Runnable() {
public void run() {
awtWindow_.dispatchEvent(new WindowEvent(awtWindow_, WindowEvent.WINDOW_CLOSING));
}
});
}
}
I have tried this, write your own code for formWindowClosing() event.
private void formWindowClosing(java.awt.event.WindowEvent evt) {
int selectedOption = JOptionPane.showConfirmDialog(null,
"Do you want to exit?",
"FrameToClose",
JOptionPane.YES_NO_OPTION);
if (selectedOption == JOptionPane.YES_OPTION) {
setVisible(false);
dispose();
} else {
setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
}
}
This asks user whether he want to exit the Frame or Application.
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
Posting what was in the question body as CW answer.
Wanted to share the results, mainly derived from following camickr's link. Basically I need to throw a WindowEvent.WINDOW_CLOSING at the application's event queue. Here's a synopsis of what the solution looks like
// closing down the window makes sense as a method, so here are
// the salient parts of what happens with the JFrame extending class ..
public class FooWindow extends JFrame {
public FooWindow() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(5, 5, 400, 300); // yeah yeah, this is an example ;P
setVisible(true);
}
public void pullThePlug() {
WindowEvent wev = new WindowEvent(this, WindowEvent.WINDOW_CLOSING);
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(wev);
}
}
// Here's how that would be employed from elsewhere -
// someplace the window gets created ..
FooWindow fooey = new FooWindow();
...
// and someplace else, you can close it thusly
fooey.pullThePlug();
If you do not want your application to terminate when a JFrame is closed,
use:
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE)
instead of:
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
From the documentation:
DO_NOTHING_ON_CLOSE (defined in WindowConstants): Don't do anything; require the program to handle the operation in the windowClosing method of a registered WindowListener object.
HIDE_ON_CLOSE (defined in WindowConstants): Automatically hide the frame after invoking any registered WindowListener objects.
DISPOSE_ON_CLOSE (defined in WindowConstants): Automatically hide and dispose the frame after invoking any registered WindowListener objects.
EXIT_ON_CLOSE (defined in JFrame): Exit the application using the System exit method. Use this only in applications.
might still be useful:
You can use setVisible(false) on your JFrame if you want to display the same frame again.
Otherwise call dispose() to remove all of the native screen resources.
copied from Peter Lang
https://stackoverflow.com/a/1944474/3782247

Categories