问题:使用 JOptionPane 会阻止我的 JPanel 切换

Problem: The use of JOptionPane stops my JPanels from switching

所以这段代码的目的是使用 JOptionPane 获取用户输入,验证它,确保输入是“Hello World”,如果是,从红色的 JPanel 切换到空白的顶部的 JLabel Hello World。但是,当在 JPanel 的文本字段中键入“Hello World”并单击“确定”时,红色的 JPanel 将被删除,但带有 JLabel 的空白面板不会出现。我使用 isDisplayable() 方法检查是否显示了带有 JLabel 的空白 JPanel,结果为真。我不确定问题是什么或如何解决。这是我的代码:

import java.awt.event.*;
import java.io.*;
import java.util.*;
import java.lang.*;
import javax.sound.sampled.Line;
import javax.swing.*;
import javax.swing.Timer;
import javax.swing.border.TitledBorder;
import java.awt.*;
import java.awt.event.*;

import static javax.swing.WindowConstants.EXIT_ON_CLOSE;

public class Main {

    private static JFrame frame = new JFrame();
    private static JPanel colorPanel = new JPanel();
    private static JPanel testPanel = new JPanel();
    private static JLabel testLabel = new JLabel("Hello World");

    public static void main(String[] args) {
        
        frame.setSize(500, 500);
        frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
        frame.setResizable(false);
        colorPanel.setBackground(Color.RED);
        frame.add(colorPanel);

        frame.setVisible(true);
        String input = JOptionPane.showInputDialog("Enter");
        if(input.equals("Hello World"))
        {
            frame.remove(colorPanel);
            frame.validate();
            frame.repaint();
            testPanel.add(testLabel);
            frame.add(testPanel);
        }

    }
}

frame.validate() 应该是 frame.revalidate() 并且应该在所有组件 adds/removes"

之后发生
if(input.equals("Hello World"))
{
    frame.remove(colorPanel);
    testPanel.add(testLabel);
    frame.add(testPanel);
    frame.revalidate();
}

我知道你已经接受了答案,但我不得不插嘴,因为我觉得虽然答案在技术上是正确的,但它可能不是最好的解决方案。

请注意,首先,您的问题与 .validate().revalidate() 关系不大,而与您调用它的位置有关。必须在完成所有更改后调用它,这意味着在删除所有组件并添加之后。

另请注意,通常最好在您的容器上安装 repaint() 并在 调用 revalidate() 之后调用它 ,尤其是在您删除组件时,因为这会帮助清除 GUI 中任何潜在的“脏”像素。

现在开始我的回答:最好不要推出您自己的解决方案,而是使用您的 GUI 库为您提供的更高级别的工具,这里是 CardLayout(教程:CardLayout Tutorial)。使用此工具,您可以轻松地向前或向后滚动“卡片”组件,这里是使用 .previous(...).next(...) 方法的 JPanel,或者通过调用 .show(...) 以灵活的方式交换组件方法。该布局还将调整使用该布局并容纳“卡片”组件的容器的大小,以便保证所有卡片都适合。

.next(...).previous(...).show(...) 的使用示例可以在下面的可编译和可运行代码中看到。另外,请看看评论:

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagLayout;
import javax.swing.*;

public class SwapPanels extends JPanel {
    private static final long serialVersionUID = 1L;
    private CardLayout cardLayout = new CardLayout(); // the layout
    private JPanel cardHolderPanel = new JPanel(cardLayout); // the JPanel that holds the cards
    
    // a combo box and model for allowing random-access swapping
    private DefaultComboBoxModel<String> comboModel = new DefaultComboBoxModel<>();
    private JComboBox<String> swapPanelCombo = new JComboBox<>(comboModel);

    public SwapPanels() {
        // listener added to combobox to allow swapping of panels
        swapPanelCombo.addActionListener(e -> swapPanel());
        
        JButton previousBtn = new JButton("Previous");
        previousBtn.addActionListener(e -> cardLayout.previous(cardHolderPanel));
        
        JButton nextBtn = new JButton("Next");
        nextBtn.addActionListener(e -> cardLayout.next(cardHolderPanel));
        
        // panel to hold buttons and combo box
        JPanel controlPanel = new JPanel();
        controlPanel.add(previousBtn);
        controlPanel.add(nextBtn);
        controlPanel.add(swapPanelCombo);
        
        // create and add our "card" JPanels, showing different colors 
        addColorPanel("White", Color.WHITE);
        addColorPanel("Red", Color.RED);
        addColorPanel("Orange", Color.ORANGE);
        addColorPanel("Yellow", Color.YELLOW);
        addColorPanel("Green", Color.GREEN);
        addColorPanel("Blue", Color.BLUE);
        addColorPanel("Cyan", Color.CYAN);
        
        // add components to the main *this* JPanel
        setPreferredSize(new Dimension(600, 450));
        setLayout(new BorderLayout());
        add(cardHolderPanel);
        add(controlPanel, BorderLayout.PAGE_END);
    }

    private void addColorPanel(String text, Color color) {
        // create color JPanel
        JPanel colorPanel = new JPanel();
        colorPanel.setBackground(color);

        // label to display color name
        JLabel label = new JLabel(text, SwingConstants.CENTER);
        
        // make label big
        label.setFont(label.getFont().deriveFont(Font.BOLD, 24f));
        
        // place label in the center of the color JPanel
        colorPanel.setLayout(new GridBagLayout());
        colorPanel.add(label);

        // add text to your jcombo box as well
        comboModel.addElement(text);

        // add color panel to the card-holder JPanel
        cardHolderPanel.add(colorPanel, text);
    }
    
    private void swapPanel() {
        // get combo box's text
        String text = (String) swapPanelCombo.getSelectedItem();
        if (text != null) {
            // use the text to swap jpanels
            cardLayout.show(cardHolderPanel, text);
        }
    }

    // be sure to show our GUI on the Swing event thread
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }

    private static void createAndShowGui() {
        SwapPanels mainPanel = new SwapPanels();
        JFrame frame = new JFrame("Swap Panels");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(mainPanel);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }
}