当前位置: 首页 > 知识库问答 >
问题:

带有子级的JPanel,该子级与父级的宽度匹配,并包装内容的高度

卞成荫
2023-03-14

我试图使jpanel(“父面板”)的内容从顶部向底部添加,并且使每个组件的宽度与父面板的宽度匹配,同时使每个组件的高度环绕内容。内容将动态生成。

这是我想要的样子:

这在Android中是相当容易做到的。我调查了Swing的布局经理,但他们似乎都不是一个明显的选择。我试过使用boxlayout(vertical),除了面板没有填充父面板的宽度(这使它看起来非常糟糕)外,它还可以工作。

(注意使用GridBagLayout、BorderLayout和GridBagConstraints的参数

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Random;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class Test extends JFrame{

    private final Color darkGreen = Color.decode("#388E3C");
    private final Color green = Color.decode("#4CAF50");
    private final Color lightGreen = Color.decode("#C8E6C9");

    public static void main(String[] args){
        Test test = new Test();
        test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    int noOfTitles = 4;
    int noOfSubTitles = 3;
    Random random = new Random();

    public Test(){


        JPanel parentPanel = new JPanel();
        this.setSize(new Dimension(300,800));
        this.setContentPane(parentPanel);
        parentPanel.setBackground(Color.white);

        //Set layout of parent panel to Gridlayout
        parentPanel.setLayout(new GridBagLayout());

        //Panel for our titles
        JPanel titlesPanel = new JPanel();
        titlesPanel.setLayout(new BoxLayout(titlesPanel, BoxLayout.Y_AXIS));

        for(int i = 0;i<noOfTitles;i++){
            //Panel for the subtitles of each title
            JPanel subTitlesPanel = new JPanel();
            subTitlesPanel.setLayout(new BoxLayout(subTitlesPanel, BoxLayout.Y_AXIS));

            for(int j = 0;j<noOfSubTitles;j++){
                //Get a panel with a title header, a collapse/uncollapse button and some sample content
                subTitlesPanel.add(getCollapsiblePanel(getSampleContent(),"Subtitle"));
                subTitlesPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0));
            }
            //Get a panel with a title header, a collapse/uncollapse button and the subtitles as content
            titlesPanel.add(getCollapsiblePanel(subTitlesPanel,"Title"));
        }

        //The constraints for the 
        GridBagConstraints constraints = new GridBagConstraints();
        constraints.anchor = GridBagConstraints.PAGE_START;
        constraints.fill = GridBagConstraints.HORIZONTAL; //Fill the panels horizontally. A weightx is needed for this to work. 
        constraints.gridx = 1;
        constraints.gridy = 0;
        constraints.weightx = 1;    //Actually makes it fill
        parentPanel.add(titlesPanel,constraints);

        //To actually bump the rest of the other stuff to the top, 
        //we need something below with a weighty > 0
        constraints.gridy = 1;
        constraints.weighty = 1;
        constraints.anchor = GridBagConstraints.PAGE_END;
        parentPanel.add(new JLabel(""),constraints);

        this.setVisible(true);
    }

    /*
     * Gets a title for the supplied content-panel. 
     * The title includes the titleText and a button for collapsing/uncollapsing the content. 
     */
    private JPanel getCollapsiblePanel(JPanel content,String titleText){
        JPanel titlePanel = new JPanel();   //Top container for the title
        JPanel title = new JPanel();        //collapse/uncollapse button and title text

        title.setLayout(new BoxLayout(title,BoxLayout.X_AXIS));
        title.add(getToggleVisibilityIcon(content));
        title.add(new JLabel(" "+titleText));

        //A border layout is needed here for the fill of the parent panel to work 
        // (I tried with the box layout but it didn't work)
        titlePanel.setLayout(new BorderLayout());
        titlePanel.add(title,BorderLayout.PAGE_START);
        titlePanel.add(content,BorderLayout.CENTER);

        //Vanity
        title.setBackground(green);
        title.setBorder(BorderFactory.createEmptyBorder(1,1,2,1));

        return titlePanel;
    }

    /*
     * Not important, just generates a panel with some "sample" strings. 
     */
    private JPanel getSampleContent(){
        JPanel content = new JPanel();
        content.setLayout(new BoxLayout(content,BoxLayout.Y_AXIS));
        for(int i = 0; i<1+random.nextInt(3); i++){
            String sampleContent = "";
            for(int j = 0;j<1 + random.nextInt(5);j++){
                sampleContent += "sample ";
            }
            JLabel sample = new JLabel(sampleContent);
            sample.setForeground(Color.decode("#111111"));
            content.add(sample);
        }
        content.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
        content.setBackground(lightGreen);
        return content;
    }

    /*
     * Method that returns a JLabel that will toggle the visibility of the 
     * supplied content panel upon clicking. 
     */
    private JLabel getToggleVisibilityIcon(JPanel content){
        JLabel icon = new JLabel(" V ");
        icon.setBackground(green);
        icon.setBorder(BorderFactory.createLineBorder(darkGreen,2));
        icon.setOpaque(true);
        icon.addMouseListener(new MouseListener(){
            private JPanel content;
            private JLabel icon;
            MouseListener init(JPanel content,JLabel icon){
                this.content = content;
                this.icon = icon;
                return this;
            }
            @Override
            public void mouseClicked(MouseEvent e) {
                if(content.isVisible()){
                    content.setVisible(false);
                    icon.setText(" > ");
                }else{
                    content.setVisible(true);
                    icon.setText(" V ");
                }
            }

            @Override
            public void mousePressed(MouseEvent e) {}
            @Override
            public void mouseReleased(MouseEvent e) {}
            @Override
            public void mouseEntered(MouseEvent e) {}
            @Override
            public void mouseExited(MouseEvent e) {}
        }.init(content,icon));
        return icon;
    }
}

正在运行的应用程序截图:

共有1个答案

訾旭
2023-03-14

没有真正理解你的问题。您通常不会有文本、按钮和组合框随机换行。通常,面板有一个布局,因此组件是有逻辑组织的。也就是说,您不想要一个带有“first name”这样的文本的标签,后面跟一个随机包装到下一行的文本字段。

在我看来,你有一个隐藏或显示的“细节面板”?

那么,您可以使用BorderLayout来实现它。因此Hide/Show按钮将放在BorderLayout.page_start中。则详细信息面板将位于BorderLayout.Center中。然后根据需要设置详细信息面板的可见性。

阅读Swing教程。有以下章节:

  1. 如何使用GridBagLayout和
  2. 如何使用边框
 类似资料:
  • 我试图理解我的意外行为: 容器中有一个最大高度为100%的元素,该容器也使用了最大高度,但意外的是,子元素溢出了父元素: 测试用例:http://jsfiddle.net/bq4Wu/16/ 但是,如果为父级指定了明确的高度,则这是固定的: 测试用例:http://jsfiddle.net/bq4Wu/17/ 有人知道第一个例子中孩子为什么不尊重父母的最大身高吗?为什么需要明确的高度?

  • 问题内容: 我的页面结构为: 现在,DIV将具有更多内容,因此DIV的高度将根据子DIV的增加而增加。 但是问题是身高没有增加。如何使它的高度等于父代的高度? 问题答案: 对于元素,添加以下属性: 然后针对这些:

  • 我有一个片段包含一个带有layout_width=“match_parent”的RecyclerView: RecyclerView中的项是CardView,也具有layout_width=“match_parent”: 我将项目视图膨胀如下: 但当我运行该应用程序时,CardView将呈现为wrap_content,如下所示: 请注意,这是在仿真器上运行的,而不是真正的设备。 是我做错了什么,还

  • 问题内容: 我有一个具有以下结构的网站: 导航在左侧,内容div在右侧。内容div的信息是通过PHP获取的,因此每次都不同。 无论加载哪个页面,如何垂直缩放导航使其高度与内容div的高度相同? 问题答案: 注意 :此答案适用于不支持Flexbox标准的旧版浏览器。 我建议您看看使用Cross-Browser CSS和NoHacks的等高列。 基本上,以与浏览器兼容的方式使用CSS做到这一点并不是一

  • 问题是要确定子数据的总和是否等于父数据。如果是,返回真,否则返回假。 下面是我的代码,在提交时出现错误。我知道这是一个简单的问题,但在编写了条件之后,我很难通过遍历所有左右节点来递归检查二叉树中每个节点的和条件。 请指导我,因为我哪里做错了。