Reputation: 15
public class Start extends JFrame{
public static void main(String...s){
Start obj = new Start();
obj.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
obj.setBounds(100,100,300,300);
JPanel main = new JPanel();
obj.add(main);
JButton btn = new JButton("Login");
main.add(btn);
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
obj.setVisible(false);
obj.dispose();
new Progress();
}
});
obj.setVisible(true);
}
}
class Progress extends JFrame{
int pro = 0;
Progress(){
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
setBounds(100,100,300,300);
JPanel main = new JPanel();
add(main);
main.add(new JLabel("ejfbasj"));
JProgressBar progressBar = new JProgressBar(0,100);
main.add(progressBar);
Thread t1 = new Thread() {
public void run() {
while(pro<=100) {
/*
* Do something - set progressbar value
* */
try {
sleep(10);
} catch (InterruptedException e) {}
progressBar.setValue(pro);
pro++;
}
}
};
t1.start();
//Do something - gives progress values
try {
t1.join();
} catch (InterruptedException e) {}
}
}
Above is Minimal, Reproducible Example of my problem.
When Progress JFrame is called from ActionListner, the JFrame doesn't appear properly. I get a black JFrame and after a sec I get final JFrame with full progressbar. But if I call new Progress()
directly, it works properly(i.e. seeing progressbar filling up).
I found that creating new Thread in UI thread is unable to draw Frame. And I should use Swing.Timer
.
I don't know how to do it with Swing.Timer
.
Any other approach is appreciated.
Upvotes: 0
Views: 134
Reputation: 168815
obj.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
There's the immediate problem, but there are so many more. Change it to the following to ensure the JRE does not exit once it is disposed:
obj.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
As to some of the other problems:
CardLayout
as shown in this answer.JDialog
instead of the 2nd frame.Throwable.printStackTrace()
Upvotes: 2
Reputation: 347184
Progress(){
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
Call setVisible
last, after you've established the UI. If you need to update the UI after it's visible, you should call invalidate
and repaint
to trigger a new layout and paint pass
Thread t1 = new Thread() {
public void run() {
while(pro<=100) {
/*
* Do something - set progressbar value
* */
try {
sleep(10);
} catch (InterruptedException e) {}
progressBar.setValue(pro);
pro++;
}
}
};
t1.start();
//Do something - gives progress values
try {
t1.join();
} catch (InterruptedException e) {}
Ok, this is actually tw problems.
First, Swing is NOT thread safe and you should not update the UI from outside the context of the Event Dispatching Thread. You should, as you said, either use a Swing Timer
or probably more suitably, a SwingWorker
Secondly, t1.join
is blocking the current thread. Because this constructor was called from the ActionListener
, this means you're in the context of the Event Dispatching Thread ie, the thread used to update the UI with, so, nothing will change until the thread is completed
For example:
I'd also discuss things about using multiple frames, setBounds
of things like pack
, setLocationRelativeTo
and using other things like borders or layout constraints to increase the padding, but there are plenty of other examples
Upvotes: 1