带有子节点的JPanel与父节点的宽度匹配并包装内容的高度

时间:2015-11-25 14:53:08

标签: java swing layout-manager

我正在尝试将JPanel("父面板")的内容从顶部添加到底部,并使每个组件的宽度与宽度相匹配父面板,同时具有每个组件的高度包装内容。内容将动态生成。

这就是我喜欢的样子:

enter image description here

这在Android中相当容易。我查看了Swing LayoutManagers,但它们似乎都不是一个明显的选择。我已经尝试使用Boxlayout(垂直),除了没有填充父面板宽度的面板之外,它的工作原理(这使得它看起来非常糟糕)。

感谢任何建议!

修改

感谢camickr的回答,我明白了。如果它将来会帮助任何人,我提供了我的代码和截图。

解决问题的代码:

(注意使用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;
    }
}

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

enter image description here

1 个答案:

答案 0 :(得分:1)

不太了解你的问题。您通常不会随机包装文本,按钮和组合框。通常,面板具有布局,因此组件在逻辑上是有组织的。那就是你不想要一个带有&#34; First Name&#34;等文字的标签。然后是一个随机包装到下一行的文本字段。

在我看来,你有一个&#34;详细的面板&#34;你隐藏或显示?

您可以使用BorderLayout实现此功能。因此隐藏/显示按钮将放置在BorderLayout.PAGE_START中。然后详细信息面板将位于BorderLayout.CENTER中。然后根据需要设置详细信息面板的可见性。

然后顶级容器可以是GridBagLayout。您可以使用约束使每行填充单元格的宽度。每个子面板都可以使用Border在左侧稍微缩进。

阅读Swing tutorial。有以下部分:

  1. 如何使用GridBagLayout和
  2. 如何使用边框