JPanel中的JPanel太多(使用GridBagLayout)

gun*_*ker 2 java swing jpanel gridbaglayout

所以基本上如果我把JPanels放在一个JPanel使用的内部GridBagLayout并且我限制了大小setPreferredSize,最终它达到了无法容纳所有这些的点,并且它展示了附图中显示的行为:

在此输入图像描述

我正在制作手风琴.这只是一个展示我遇到的问题的例子.手风琴的每个部分都可以单独打开,它们具有任意大小,可以随时添加.它很容易达到所有单个面板的高度,并将它们与总高度进行比较,但是当添加太多时,它表现出我所展示的嘎吱嘎吱的行为.这也缩小了高度,因此更难以确定何时发生嘎吱嘎吱声.我必须缓存高度,并以某种方式预先计算新部件的高度.最终目标是在添加新面板并且没有足够空间时移除旧面板.

有没有一种简单的方法来确定如果它没有受到限制会有什么高度,或者可能是一种支持的方法来检测何时发生这样的嘎吱嘎吱(所以我可以在再次涂漆之前快速将其稀释)?使得GridBagLayout行为像其他布局一样并且溢出到Hammerspace而不是压缩的选项也会起作用.

代码例如:

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

public class FoldDrag extends JLayeredPane {
    public TexturedPanel backingPanel = new TexturedPanel(new GridBagLayout(),"data/gui/grayerbricks.png");
    static JPanel windowbase=new JPanel();
    static JPanel restrictedpanel=new JPanel(new GridBagLayout());

    GridBagConstraints gbc = new GridBagConstraints();

    public FoldDrag() {
        JButton addpan  = new JButton("Add things");
        windowbase.add(addpan);
        windowbase.add(restrictedpanel);
        restrictedpanel.setBackground(Color.red);
        restrictedpanel.setPreferredSize(new Dimension(200,200));
        gbc.weighty=1;
        gbc.weightx=1;
        gbc.gridx=0;
        gbc.gridy=0;
        gbc.gridheight=1;
        gbc.gridwidth=1;
        gbc.fill=GridBagConstraints.HORIZONTAL;
        addpan.addActionListener(new ActionListener() {
            int number=0;
            @Override
            public void actionPerformed(ActionEvent e)
            {
                number++;
                gbc.gridy=number;
                JPanel tmppanel = new JPanel();
                tmppanel.setPreferredSize(new Dimension(100,30));
                if(number%3==0)
                    tmppanel.setBackground(Color.blue);
                if(number%3==1)
                    tmppanel.setBackground(Color.yellow);
                if(number%3==2)
                    tmppanel.setBackground(Color.green);
                restrictedpanel.add(tmppanel,gbc);
                restrictedpanel.validate();
            }
        });
        windowbase.setVisible(true);
    }
    private static void createAndShowUI() {
        JFrame frame = new JFrame("DragLabelOnLayeredPane");
        frame.getContentPane().add(windowbase);
        FoldDrag thedrag=new FoldDrag();
        windowbase.add(thedrag);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setPreferredSize(new Dimension(300,300));
        frame.pack();
        frame.setResizable(true);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        out.active=true;
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                createAndShowUI();
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:似乎我没有很好地描述我的手风琴版本.这是一个链接.

Mad*_*mer 5

您有特殊的要求,通过使用它的布局管理器可以更好地服务.这使您能够控制布局的各个方面,而无需诉诸黑客或"解决方法",这些工作从未完全奏效或具有奇怪的副作用

手风琴布局

public class AccordionLayout implements LayoutManager {

    // This "could" be controlled by constraints, but that would assume
    // that more then one component could be expanded at a time
    private Component expanded;

    public void setExpanded(Component expanded) {
        this.expanded = expanded;
    }

    public Component getExpanded() {
        return expanded;
    }

    @Override
    public void addLayoutComponent(String name, Component comp) {
    }

    @Override
    public void removeLayoutComponent(Component comp) {
    }

    @Override
    public Dimension preferredLayoutSize(Container parent) {
        Dimension size = minimumLayoutSize(parent);
        if (expanded != null) {
            size.height -= expanded.getMinimumSize().height;
            size.height += expanded.getPreferredSize().height;
        }

        return size;
    }

    @Override
    public Dimension minimumLayoutSize(Container parent) {
        int height = 0;
        int width = 0;
        for (Component comp : parent.getComponents()) {
            width = Math.max(width, comp.getPreferredSize().width);
            height += comp.getMinimumSize().height;
        }
        return new Dimension(width, height);
    }

    @Override
    public void layoutContainer(Container parent) {

        Insets insets = parent.getInsets();
        int availableHeight = parent.getHeight() - (insets.top + insets.bottom);
        int x = insets.left;
        int y = insets.top;

        int maxSize = 0;
        Dimension minSize = minimumLayoutSize(parent);
        if (expanded != null) {
            minSize.height -= expanded.getMinimumSize().height;
            // Try an honour the preferred size the expanded component...
            maxSize = Math.max(expanded.getPreferredSize().height, availableHeight - minSize.height);
        }

        int width = parent.getWidth() - (insets.left + insets.right);
        for (Component comp : parent.getComponents()) {
            if (expanded != comp) {
                comp.setSize(width, comp.getMinimumSize().height);
            } else {
                comp.setSize(width, maxSize);
            }
            comp.setLocation(x, y);
            y += comp.getHeight();
        }

    }

}
Run Code Online (Sandbox Code Playgroud)

可运行的例子......

这就是enth度,创建一个专门的组件来充当每个"折叠",但这只是从外部降低了API的复杂性,这意味着,你只需要考虑标题和内容,然后让剩下的API会照顾好自己

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private AccordionLayout layout;

        public TestPane() {
            layout = new AccordionLayout();
            setLayout(layout);

            AccordionListener listener = new AccordionListener() {
                @Override
                public void accordionSelected(Component comp) {
                    layout.setExpanded(comp);
                    revalidate();
                    repaint();
                }
            };

            Color colors[] = {Color.RED, Color.BLUE, Color.CYAN, Color.GREEN, Color.MAGENTA, Color.ORANGE, Color.PINK, Color.YELLOW};
            String titles[] = {"Red", "Blue", "Cyan", "Green", "Magenta", "Orange", "Pink", "Yellow"};
            for (int index = 0; index < colors.length; index++) {
                AccordionPanel panel = new AccordionPanel(titles[index], new ContentPane(colors[index]));
                panel.setAccordionListener(listener);
                add(panel);
            }
        }

    }

    public class ContentPane extends JPanel {

        public ContentPane(Color background) {
            setBackground(background);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(100, 100);
        }

    }

    public interface AccordionListener {

        public void accordionSelected(Component comp);

    }

    public class AccordionPanel extends JPanel {

        private JLabel title;
        private JPanel header;
        private Component content;

        private AccordionListener accordionListener;

        public AccordionPanel() {
            setLayout(new BorderLayout());

            title = new JLabel("Title");

            header = new JPanel(new FlowLayout(FlowLayout.LEADING));
            header.setBackground(Color.GRAY);
            header.setBorder(new LineBorder(Color.BLACK));
            header.add(title);
            add(header, BorderLayout.NORTH);

            header.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    AccordionListener listener = getAccordionListener();
                    if (listener != null) {
                        listener.accordionSelected(AccordionPanel.this);
                    }
                }
            });
        }

        public AccordionPanel(String title) {
            this();
            setTitle(title);
        }

        public AccordionPanel(String title, Component content) {
            this(title);
            setContentPane(content);
        }

        public void setAccordionListener(AccordionListener accordionListener) {
            this.accordionListener = accordionListener;
        }

        public AccordionListener getAccordionListener() {
            return accordionListener;
        }

        public void setTitle(String text) {
            title.setText(text);
            revalidate();
        }

        public String getText() {
            return title.getText();
        }

        public void setContentPane(Component content) {
            if (this.content != null) {
                remove(this.content);
            }

            this.content = content;
            if (this.content != null) {
                add(this.content);
            }
            revalidate();
        }

        public Component getContent() {
            return content;
        }

        @Override
        public Dimension getMinimumSize() {
            return header.getPreferredSize();
        }

        @Override
        public Dimension getPreferredSize() {
            Dimension size = content != null ? content.getPreferredSize() : super.getPreferredSize();
            Dimension min = getMinimumSize();
            size.width = Math.max(min.width, size.width);
            size.height += min.height;
            return size;
        }

    }

    public class AccordionLayout implements LayoutManager {

        // This "could" be controled by constraints, but that would assume
        // that more then one component could be expanded at a time
        private Component expanded;

        public void setExpanded(Component expanded) {
            this.expanded = expanded;
        }

        public Component getExpanded() {
            return expanded;
        }

        @Override
        public void addLayoutComponent(String name, Component comp) {
        }

        @Override
        public void removeLayoutComponent(Component comp) {
        }

        @Override
        public Dimension preferredLayoutSize(Container parent) {
            Dimension size = minimumLayoutSize(parent);
            if (expanded != null) {
                size.height -= expanded.getMinimumSize().height;
                size.height += expanded.getPreferredSize().height;
            }

            return size;
        }

        @Override
        public Dimension minimumLayoutSize(Container parent) {
            int height = 0;
            int width = 0;
            for (Component comp : parent.getComponents()) {
                width = Math.max(width, comp.getPreferredSize().width);
                height += comp.getMinimumSize().height;
            }
            return new Dimension(width, height);
        }

        @Override
        public void layoutContainer(Container parent) {

            Insets insets = parent.getInsets();
            int availableHeight = parent.getHeight() - (insets.top + insets.bottom);
            int x = insets.left;
            int y = insets.top;

            int maxSize = 0;
            Dimension minSize = minimumLayoutSize(parent);
            if (expanded != null) {
                minSize.height -= expanded.getMinimumSize().height;
                // Try an honour the preferred size the expanded component...
                maxSize = Math.max(expanded.getPreferredSize().height, availableHeight - minSize.height);
            }

            int width = parent.getWidth() - (insets.left + insets.right);
            for (Component comp : parent.getComponents()) {
                if (expanded != comp) {
                    comp.setSize(width, comp.getMinimumSize().height);
                } else {
                    comp.setSize(width, maxSize);
                }
                comp.setLocation(x, y);
                y += comp.getHeight();
            }

        }

    }

}
Run Code Online (Sandbox Code Playgroud)

现在,如果你真的想要挑战,你可以使用一些动画布局代理,并做一些像...

动画布局