有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

SwingJavaCardLayout。show()不显示

我在“阻塞”代码之前使用.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()调用,以便在继续循环之前真正花时间切换窗格


共 (3) 个答案

  1. # 1 楼答案

    这是因为重新绘制UI与事件处理在同一线程中完成,直到事件处理完成(即,所有事件处理方法都已返回)后才会发生

    最好的办法是将“阻塞”代码移动到可运行的程序中,并在工作线程中执行

  2. # 2 楼答案

    这是因为您正在处理EventDispatchingThread。该线程还负责实际绘制GUI

    你别无选择,只能在另一个线程中工作

    例如:(快+脏)

    new Thread(){
        @Override
        public void run() {
            while (...) {...}
        }
    }.start();
    
  3. # 3 楼答案

    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.

    是的,因为您正在“阻止”负责重新绘制GUI的事件调度线程(EDT)。因此,在代码完成执行之前,GUI无法重新绘制自身

    您需要创建一个单独的线程来执行长时间运行的任务,这样就不会阻塞EDT。一种方法是使用SwingWorker。SwingWorker将为您创建线程,并在任务完成时通知您,以便您更新GUI

    阅读Swing教程中关于Concurrency的部分,了解更多信息和工作示例