SetVisible(false) 更改面板中组件的布局

Posted

技术标签:

【中文标题】SetVisible(false) 更改面板中组件的布局【英文标题】:SetVisible(false) changes the layout of my components within my Panel 【发布时间】:2011-09-02 17:39:05 【问题描述】:

当我将其中一个子面板设置为不可见时,如何使主面板中的子面板保持原位?

我的样子:

[ (Panel1) (Panel2) (Panel3) (Panel4) ]

当我执行panel3.setVisible(false) 时,它看起来像:

[      (Panel1) (Panel2) (Panel4)     ]

我希望它看起来像:

[ (Panel1) (Panel2)          (Panel4) ]

我正在使用 GridBagLayout,我的 mainPanel 声明如下所示:

final JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();

然后我添加了一个新面板,例如:

final JTextField valueTextField = new JTextField();
valueTextField.setPreferredSize(new Dimension(80, 25));
valueTextField.setName("Value");
c.gridx =0;
panel.add(valueTextField, c);

如果需要,我会提供更多代码,我不在乎我使用哪种布局,只要它能得到我想要的。

【问题讨论】:

【参考方案1】:

我相信所有布局管理器都尊重组件的可见性,不会在首选大小和布局计算中包含不可见的组件。

一种解决方案可能是使用 OverlayLayout 将所有面板包装在一个面板中:

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

public class OverlayLayoutInvisible

    public static void main(String[] args)
    
        JPanel panel = new JPanel();
        panel.add( createPanel("Button 1") );
        panel.add( createPanel("Button 2") );
        panel.add( createPanel("Button 3") );
        panel.add( createPanel("Button 4") );
        panel.add( createPanel("Button 5") );

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.add( panel );
        frame.pack();
        frame.setLocationRelativeTo( null );
        frame.setVisible(true);
    

    public static JPanel createPanel(String text)
    
        JButton button = new JButton( text );
        button.addActionListener( new ActionListener()
        
            public void actionPerformed(ActionEvent e)
            
                Component c = (Component)e.getSource();
                c.setVisible(false);
            
        );

        InvisibleComponent ic = new InvisibleComponent( button );

        JPanel panel = new JPanel();
        panel.setLayout( new OverlayLayout(panel) );
        panel.add( ic );
        panel.add( button );


        return panel;
    

    public static class InvisibleComponent extends JComponent
    
        private Component master;

        public InvisibleComponent(Component master)
        
            this.master = master;
            setAlignmentX( master.getAlignmentX() );
            setAlignmentY( master.getAlignmentY() );
        

        public Dimension getPreferredSize()
        
            return master.getPreferredSize();
        
    

【讨论】:

请注意,关于“所有布局尊重可见性”的评论只是部分正确。在这种情况下,一些布局有关于行为的选项(MigLayout 有,我认为 GroupLayout 也有)。 DesignGridLayout 不关心组件的可见性:添加的组件以相同的方式布局,可见与否。 +1 让我傻眼。在我检查 JavaDocs 之前,我以为您指的是自定义布局!文档。 @since标签有点薄,什么时候引入的? @Andrew Thompson,从我记事起它就一直存在,但我从来没有发现它那么有用。我似乎记得在理解组件大小不同时如何在面板中定位组件时遇到问题。此外,您必须小心如何对组件进行分层。例如,如果您将标签放在按钮顶部。该按钮将在鼠标悬停时绘制标签的顶部,因为该按钮会获得 mouseover 事件并绘制按钮的翻转效果。 谢谢。从那以后,我注意到 Java 教程似乎没有涵盖它。也许 Swing 开发人员对OverlayLayout 感到有些尴尬(它一直让我想起 Beck - 与 Odelay 押韵)。 ;)【参考方案2】:

我建议在单个单元格中使用CardLayout,而不是将其设置为不可见,而是切换到空面板。

下面的代码演示了这一点。在hidePanel() 中,有两个选项可以隐藏当前启用了CardLayout 路由的单元格。

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

public class InvisiblePanels 
    public static void main(String... args) throws Exception 
        JFrame frame = new JFrame();
        frame.setLayout(new GridBagLayout());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        GridBagConstraints c = new GridBagConstraints();
        c.gridx = 0;
        frame.add(new MyPanel(), c);
        c.gridx = 1;
        frame.add(new MyPanel(), c);
        c.gridx = 2;
        frame.add(new MyPanel(), c);

        frame.pack();
        frame.setVisible(true);

    

    private static class MyPanel extends JPanel 

        CardLayout layout;

        public MyPanel() 
            layout = new CardLayout();
            setLayout(layout);
            JButton button = new JButton("Click me");
            button.addActionListener(new ActionListener() 
                public void actionPerformed(ActionEvent e) 
                    hidePanel();
                
            );
            add(button, "visible");
            add(new JPanel(), "invisible");
            layout.show(this, "visible");
        

        public void hidePanel() 
//            setVisible(false);
            layout.show(this, "invisible");
        
    

【讨论】:

【参考方案3】:

您也许可以调整 GridLayout(您有 SSCCE 吗?)

否则:

将 Panel3 和 Panel4 放在您添加到 GridBagLayout 的单个面板中。然后在 FlowLayout(左对齐,首选大小)、BorderLayout、GridLayout 等布局中设置新面板。

【讨论】:

以上是关于SetVisible(false) 更改面板中组件的布局的主要内容,如果未能解决你的问题,请参考以下文章

Java Swing dispose() 与 setVisible(false)

调用 setVisible(false) 在 QWidget 的构造函数中不起作用

Java:语句未按顺序执行

未调用浮动树面板的模糊侦听器

setVisible() 和正在绘制的组件之间会发生啥?

如何在运行时动态更改组件模板?角 4