Show ProgressBar with windowClosing(WindowEvent we) - java

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.

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();
}
});

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.

How is a JDialog's owner still updating it's UI even when it's EDT is blocked?

I have the following example code:
public class MainWindow extends JFrame implements ActionListener {
public MainWindow() {
JButton openButton = new JButton('Open');
openButton.addActionListener(this);
add(openButton);
}
public void actionPerformed(ActionEvent e) {
// Create and show a modal dialog.
JDialog dialog = new JDialog(this, true);
dialog.setVisible(true);
}
}
When I click the openButton it calls actionPerformed(ActionEvent e) on the event dispatch thread and dialog.setVisible(true) blocks it.
But with more sophisticated frames I notice that they still update their UI from non user generated events such as a Timer action.
In any other case that I block the EDT my UI completely hangs, but when dialog.setVisible(true) blocks the EDT the owner's UI continues to update.
So my question is how does this work?

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

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.

Component in a JScrollPane stops receiving KeyEvents

I am putting a component ( derivative on JPanel ) inside a JScrollPane.
scrollPane = new JScrollPane(component);
since the component occasionally changes size, I have to occasionally do :
SwingUtilities.invokeLater(new Runnable(){
public void run()
{
scrollPane.getViewport().setView(component);
component.repaint();
}
});
Also, the component can receive KeyEvents
component.addKeyListener(this);
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
component.setFocusable(true);
component.requestFocusInWindow();
}
});
However, the component never receives any Key Events. Even the code in keyTyped() does not execute ( I put a System.out.println() there).
What is more baffling, is, in debug mode, I can pause the main thread, when the AWT event thread would accept key events. But during normal execution, it does not work.
Can anyone suggest what I am doing wrong ?
Making my component java.swing.Scrollable, and replacing scrollPane.getViewport().setView(component);
with component.revalidate solved my prioblem.
Thanks ordnungswidrig!

Categories