Java CardLayout .show() 未显示
Java CardLayout .show() not showing
我在 "blocking" 代码之前使用 .show()
,就像 while 循环一样。但是即使调用了 .show,UI 实际上并没有显示调用的面板。
这是显示问题的代码:
(警告:此代码包含一个 while true 循环。)
import javax.swing.JFrame;
import java.awt.CardLayout;
import java.awt.event.ActionEvent;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JButton;
public class CardTest extends JFrame{
public CardTest() {
CardLayout cl = new CardLayout(0,0);
getContentPane().setLayout(cl);
JPanel panelA = new JPanel();
getContentPane().add(panelA, "PanelA");
JLabel lblPanelA = new JLabel("Panel A");
panelA.add(lblPanelA);
JButton btnSwitchToPanel = new JButton("Switch to Panel B");
panelA.add(btnSwitchToPanel);
JPanel panelB = new JPanel();
getContentPane().add(panelB, "PanelB");
JLabel lblPanelB = new JLabel("Panel B");
panelB.add(lblPanelB);
btnSwitchToPanel.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent event) {
cl.show(getContentPane(), "PanelB");
getContentPane().revalidate();
// Here is the problem. Even though cl.show is called first,
// it still doesn't show, before the while loop has terminated.
int i = 0;
while(i < 1000000){
i++;
System.out.println(i);
}
}
});
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
}
public static void main(String[] args){
new CardTest();
}
}
如果您想知道,我需要这个用于下载器,在第一个面板中按下按钮后调用 while true 循环(下载文件)。第二个面板包含进度条。但是即使在下载代码之前调用了 .show 函数,进度面板也永远不会显示。
更新
我知道将循环放入一个新线程,解决了绘制问题,但它也引入了其他问题,因为我依赖于循环后的函数顺序执行(下载文件(循环),解压缩文件,移动那些文件...)。
最好的解决方案是找到一种方法,让 .show() 调用在继续循环之前实际花时间切换窗格。
发生这种情况是因为您正在处理 EventDispatchingThread。该线程还负责实际绘制 GUI。
您别无选择,只能在另一个线程中完成您的工作。
例如:(快 + 脏)
new Thread(){
@Override
public void run() {
while (...) {...}
}
}.start();
这是因为重绘 UI 是在与事件处理相同的线程中完成的,并且直到事件处理完成(即所有事件处理方法都已返回)后才会发生。
最好的办法是将 "blocking" 代码移动到可运行的程序中并在工作线程中执行它。
I use .show() before a "blocking" code like a while loop. But even though the .show gets called, the UI doesn't actually show the called panel.
是的,因为您是 "blocking" 负责重新绘制 GUI 的事件调度线程 (EDT)。因此,在代码执行完毕之前,GUI 无法重新绘制自身。
您需要创建一个单独的线程来执行长 运行 任务,这样您就不会阻塞 EDT。一种方法是使用 SwingWorker
。 SwingWorker 将为您创建线程,并在任务完成时通知您,以便您更新 GUI。
阅读有关 Concurrency 的 Swing 教程部分,了解更多信息和工作示例。
我在 "blocking" 代码之前使用 .show()
,就像 while 循环一样。但是即使调用了 .show,UI 实际上并没有显示调用的面板。
这是显示问题的代码: (警告:此代码包含一个 while true 循环。)
import javax.swing.JFrame;
import java.awt.CardLayout;
import java.awt.event.ActionEvent;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JButton;
public class CardTest extends JFrame{
public CardTest() {
CardLayout cl = new CardLayout(0,0);
getContentPane().setLayout(cl);
JPanel panelA = new JPanel();
getContentPane().add(panelA, "PanelA");
JLabel lblPanelA = new JLabel("Panel A");
panelA.add(lblPanelA);
JButton btnSwitchToPanel = new JButton("Switch to Panel B");
panelA.add(btnSwitchToPanel);
JPanel panelB = new JPanel();
getContentPane().add(panelB, "PanelB");
JLabel lblPanelB = new JLabel("Panel B");
panelB.add(lblPanelB);
btnSwitchToPanel.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent event) {
cl.show(getContentPane(), "PanelB");
getContentPane().revalidate();
// Here is the problem. Even though cl.show is called first,
// it still doesn't show, before the while loop has terminated.
int i = 0;
while(i < 1000000){
i++;
System.out.println(i);
}
}
});
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
}
public static void main(String[] args){
new CardTest();
}
}
如果您想知道,我需要这个用于下载器,在第一个面板中按下按钮后调用 while true 循环(下载文件)。第二个面板包含进度条。但是即使在下载代码之前调用了 .show 函数,进度面板也永远不会显示。
更新
我知道将循环放入一个新线程,解决了绘制问题,但它也引入了其他问题,因为我依赖于循环后的函数顺序执行(下载文件(循环),解压缩文件,移动那些文件...)。
最好的解决方案是找到一种方法,让 .show() 调用在继续循环之前实际花时间切换窗格。
发生这种情况是因为您正在处理 EventDispatchingThread。该线程还负责实际绘制 GUI。
您别无选择,只能在另一个线程中完成您的工作。
例如:(快 + 脏)
new Thread(){
@Override
public void run() {
while (...) {...}
}
}.start();
这是因为重绘 UI 是在与事件处理相同的线程中完成的,并且直到事件处理完成(即所有事件处理方法都已返回)后才会发生。
最好的办法是将 "blocking" 代码移动到可运行的程序中并在工作线程中执行它。
I use .show() before a "blocking" code like a while loop. But even though the .show gets called, the UI doesn't actually show the called panel.
是的,因为您是 "blocking" 负责重新绘制 GUI 的事件调度线程 (EDT)。因此,在代码执行完毕之前,GUI 无法重新绘制自身。
您需要创建一个单独的线程来执行长 运行 任务,这样您就不会阻塞 EDT。一种方法是使用 SwingWorker
。 SwingWorker 将为您创建线程,并在任务完成时通知您,以便您更新 GUI。
阅读有关 Concurrency 的 Swing 教程部分,了解更多信息和工作示例。