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 教程部分,了解更多信息和工作示例。