英文:
JFrame not showing up properly when called from ActionListener
问题
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);
Timer timer = new Timer(10, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (pro <= 100) {
progressBar.setValue(pro);
pro++;
}
}
});
timer.start();
}
}
Note: The translation above only includes the translated code part as requested. If you have any questions or need further assistance, feel free to ask.
英文:
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);
}
}
<br/>
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.
答案1
得分: 2
obj.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
有一个即时的问题,但还有很多其他问题。将其更改为以下内容,以确保在销毁后 JRE 不会退出:
obj.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
至于其他一些问题:
- 参见[使用多个 JFrames,是好还是坏的实践?](http://stackoverflow.com/q/9554636/418556) 在这种情况下,我建议在将每个 GUI 重构为面板后,采取以下两种方法之一:
1. 使用 [`CardLayout`](http://download.oracle.com/javase/8/docs/api/java/awt/CardLayout.html) 将两个面板都显示在一个框架中,如[此答案中所示](http://stackoverflow.com/a/5786005/418556)。
2. 使用 `JDialog` 替代第二个框架。
- 始终在事件分派线程上启动和更新 GUI。不这样做会导致不可预测的差异。
- 不要忽略异常!它们准确地告诉我们出了什么问题。除非实施了日志记录,至少调用 `Throwable.printStackTrace()`
英文:
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:
- See The Use of Multiple JFrames, Good/Bad Practice? In this case I'd recommend one of two approaches, after refactoring each GUI into a panel:
- Display both panels in one frame using
CardLayout
as shown in this answer. - Use a
JDialog
instead of the 2nd frame.
- Display both panels in one frame using
- Always start and update the GUI on the Event Dispatch Thread. Not doing so causes unpredictable differences.
- Don't ignore exceptions! They inform us exactly what went wrong. Unless logging is implemented, at least call
Throwable.printStackTrace()
答案2
得分: 1
问题 #1
Progress(){
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
在建立UI之后,最后调用setVisible
。如果需要在UI可见后更新UI,您应该调用invalidate
和repaint
以触发新的布局和绘制过程。
问题 #2
Thread t1 = new Thread() {
public void run() {
while(pro<=100) {
/*
* 做一些事情 - 设置进度条的值
* */
try {
sleep(10);
} catch (InterruptedException e) {}
progressBar.setValue(pro);
pro++;
}
}
};
t1.start();
// 做一些事情 - 提供进度值
try {
t1.join();
} catch (InterruptedException e) {}
好的,实际上这是两个问题。
首先,Swing不是线程安全的,您不应该从事件分派线程之外的上下文更新UI。正如您所说,您应该使用Swing Timer
,或者可能更合适的是SwingWorker
。
其次,t1.join
正在阻塞当前线程。因为这个构造函数是从ActionListener
中调用的,这意味着您在事件分派线程的上下文中,即用于更新UI的线程上下文中,所以在线程完成之前不会有任何变化。
例如:
- https://stackoverflow.com/questions/12020949/jprogressbar-isnt-progressing/12021971#12021971
- https://stackoverflow.com/questions/13094666/jprogressbar-wont-update/13095992#13095992
其他问题...
我还想讨论一些关于使用多个框架,setBounds
、pack
、setLocationRelativeTo
之类的内容,以及使用边框或布局约束等其他内容,以增加填充,但是已经有很多其他的示例了。
英文:
Problem #1
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
Problem #2
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:
- https://stackoverflow.com/questions/12020949/jprogressbar-isnt-progressing/12021971#12021971
- https://stackoverflow.com/questions/13094666/jprogressbar-wont-update/13095992#13095992
Other problems...
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论