java - Swing:隐藏的 JPanel 添加的尺寸等于 0 时,在变为可见时不会重新计算

标签 java swing jpanel layout-manager repaint

我的程序有两个面板,一个左侧有 2 个切换按钮,一个右侧显示标签。
选择后,每个按钮都会在右侧区域添加其面板(并将其他按钮设置为不可见)。
取消选择后,他们会将其删除。
在最后一种情况下,我希望其他面板(如果添加到容器中)变得可见。

该代码基本上可以工作,但如果在开始面板上取消选择第二个按钮,则不会出现 1。
我发现面板 1 的尺寸设置为 0,如果我手动设置此尺寸,面板就会出现。不幸的是,这样做布局管理器会停止处理面板尺寸(当我调整窗口或 JSplitPanel 的大小时,这很糟糕!)。

public static void main(final String[] args) {
    SwingUtilities.invokeLater(new Runnable() {

        @Override
        public void run() {
            final JFrame frame = new JFrame();
            frame.setSize(800, 800);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            final JPanel buttonsPanel = new JPanel(new FlowLayout());
            final JToggleButton btn1 = new JToggleButton("Button 1");
            final JToggleButton btn2 = new JToggleButton("Button 2");

            buttonsPanel.add(btn1);
            buttonsPanel.add(btn2);

            final JPanel containerPanel = new JPanel(new BorderLayout());
            final JPanel pan1;
            final JPanel pan2;
            pan1 = new JPanel(new BorderLayout());
            pan2 = new JPanel(new BorderLayout());

            pan1.add(new JLabel("panel 1"));
            pan2.add(new JLabel("panel 2"));

            pan1.setBackground(Color.WHITE);
            pan2.setBackground(Color.RED);

            btn1.addItemListener(new ItemListener() {

                @Override
                public void itemStateChanged(final ItemEvent e) {
                    final int state = e.getStateChange();
                    for (final Component component : containerPanel.getComponents()) {
                        component.setVisible(false);
                    }

                    if (state == ItemEvent.SELECTED) {
                        containerPanel.add(pan1, BorderLayout.CENTER);
                        pan1.setVisible(true);
                    }
                    else {
                        containerPanel.remove(pan1);
                        for (final Component component : containerPanel.getComponents()) {
                            component.setVisible(true);
                            break;
                        }
                    }
                    containerPanel.invalidate();
                    containerPanel.repaint();
                }
            });

            btn2.addItemListener(new ItemListener() {

                @Override
                public void itemStateChanged(final ItemEvent e) {
                    final int state = e.getStateChange();
                    for (final Component component : containerPanel.getComponents()) {
                        component.setVisible(false);
                    }

                    if (state == ItemEvent.SELECTED) {
                        pan2.setVisible(true);
                        containerPanel.add(pan2, BorderLayout.CENTER);
                    }
                    else {
                        containerPanel.remove(pan2);
                        for (final Component component : containerPanel.getComponents()) {
                            component.setVisible(true);
                            // component.setSize(containerPanel.getSize());
                            break;
                        }
                    }
                    containerPanel.revalidate();
                    containerPanel.repaint();
                }
            });

            btn1.setSelected(true);
            btn2.setSelected(true);

            final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
                                                        true,
                                                        buttonsPanel,
                                                        containerPanel);
            splitPane.setResizeWeight(0.5);
            frame.add(splitPane);
            frame.setVisible(true);

        }
    });

}

如何在不手动设置其他面板尺寸的情况下解决此问题? 我知道 CardLayout 是此类需求的解决方案,但不幸的是它不适用于我的问题。

谢谢

编辑: 正如评论中所要求的,这里有一个简单的操作序列来解释问题:

我的期望:

  1. 启动应用程序 -> 两个按钮都被选中,两个面板都添加到右侧容器中,只有面板 2 可见(因为按钮 2 是代码最后选择的)。
  2. 取消选择按钮 2 -> 面板 2 从右侧容器中删除,面板 1 切换为可见并显示在右侧容器中。

到底发生了什么:

  1. 与预期相同
  2. 面板 1 未显示,因为其尺寸均为 0,无效和重绘不起作用

最佳答案

"both panels are added to the right container, only panel 2 is visible"

这是不正确的。您正在使用 BorderLayout。问题是每个位置只能有一个组件。第一个被踢出(容器中不再存在),仅保留最后一个添加的,并且您正在尝试将两者添加到 CENTER

因此,您认为通过删除第二个面板,当您调用 setVisible 时第一个面板将自动出现,这是不正确的。该组件实际上需要再次添加。

根据这些新信息,尝试调试您的问题。还可以使用 revalidate() 而不是 invalidate()

"panel 1 is not shown because its dimensions are both 0"

与此无关。 BorderLayout 不关心大小。它将拉伸(stretch)面板以适应。

<小时/>

旁白:这是 CardLayout 的完美情况。不太确定为什么你不能使用它,但也许你应该更深入地研究实现它的可能性

<小时/>

更新

我想这可能就是您正在寻找的。只需切换另一个按钮的状态即可。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Test {

    public static void main(final String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                final JFrame frame = new JFrame();
                frame.setSize(800, 800);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                final JPanel buttonsPanel = new JPanel(new FlowLayout());
                final JToggleButton btn1 = new JToggleButton("Button 1");
                final JToggleButton btn2 = new JToggleButton("Button 2");

                buttonsPanel.add(btn1);
                buttonsPanel.add(btn2);

                final JPanel containerPanel = new JPanel(new BorderLayout());
                final JPanel pan1;
                final JPanel pan2;
                pan1 = new JPanel(new BorderLayout());
                pan2 = new JPanel(new BorderLayout());

                pan1.add(new JLabel("panel 1"));
                pan2.add(new JLabel("panel 2"));

                pan1.setBackground(Color.WHITE);
                pan2.setBackground(Color.RED);

                btn1.addItemListener(new ItemListener() {

                    @Override
                    public void itemStateChanged(final ItemEvent e) {
                        final int state = e.getStateChange();

                        if (state == ItemEvent.SELECTED) {
                            containerPanel.add(pan1, BorderLayout.CENTER);
                            containerPanel.remove(pan2);
                            btn2.getModel().setSelected(false);
                        } else {
                            containerPanel.add(pan2, BorderLayout.CENTER);
                            containerPanel.remove(pan1);
                            btn2.getModel().setSelected(true);
                        }
                        containerPanel.revalidate();
                        containerPanel.repaint();
                    }
                });

                btn2.addItemListener(new ItemListener() {

                    @Override
                    public void itemStateChanged(final ItemEvent e) {
                        final int state = e.getStateChange();
                        if (state == ItemEvent.SELECTED) {
                            containerPanel.add(pan2, BorderLayout.CENTER);
                            containerPanel.remove(pan1);
                            btn1.getModel().setSelected(false);
                        } else {
                            containerPanel.add(pan1, BorderLayout.CENTER);
                            containerPanel.remove(pan2);
                            btn1.getModel().setSelected(true);
                        }

                        containerPanel.revalidate();
                        containerPanel.repaint();
                    }
                });

                btn1.setSelected(true);
                btn2.setSelected(true);

                final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
                        true,
                        buttonsPanel,
                        containerPanel);
                splitPane.setResizeWeight(0.5);
                frame.add(splitPane);
                frame.setVisible(true);

            }
        });
    }
}

关于java - Swing:隐藏的 JPanel 添加的尺寸等于 0 时,在变为可见时不会重新计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25684969/

相关文章:

java - 如何从 try/catch block 中获取变量?

java - 无法使用 Lambda 中的 SQS

java - 在围绕屏幕移动球的情况下,如何正确处理 JComponent 的按键和重绘?

java - JSON 反序列化时的 Base64 解码值

Java 使用更逻辑的 ScrollBar 进行滚动

java - SpringLayout 中的组件大小

java - JPopupMenu 没有像它应该的那样消失

java - 将面板放置在网格布局上时如何消除面板之间的间隙?

java - 当我导出 Java 程序时,为什么出现框架而不出现面板?

java - JPA:查找所有具有一组通用标签的文章