本文介绍了JPanel中的JPanel太多(使用GridBagLayout)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 29岁程序员,3月因学历无情被辞! 所以基本上如果我把 JPanel s放在 JPanel 中,它使用 GridBagLayout 并且我使用 setPreferredSize 限制大小,最终它达到了无法容纳所有这些大小的点,并且它显示了所附的行为图片: 我正在制作手风琴。这只是展示我遇到的问题的一个例子。手风琴的每个部分都可以单独打开,它们具有任意大小,可以随时添加。它很容易达到所有单个面板的高度,并将它们与总高度进行比较,但是当添加太多时,它表现出我所展示的嘎吱嘎吱的行为。这也缩小了高度,因此更难以确定何时发生嘎吱嘎吱声。我必须缓存高度,并以某种方式预先计算新部件的高度。最终目标是在添加新面板并且没有足够空间时移除旧面板。 是否有一种简单的方法可以确定某些高度如果它没有受到限制,或者可能是一种支持的方式来检测何时发生这样的嘎吱嘎吱声(所以我可以在再次涂漆之前快速将其稀释)?使 GridBagLayout 的选项与其他布局一样,并溢出到 公共类AccordionLayout实现LayoutManager { //这个可以受约束条件控制,但假设 //可以在私有组件扩展的时候扩展一个以上的组件; public void setExpanded(扩展组件){ 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; } 返回大小; } @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; } 返回新的尺寸(宽度,高度); } @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; //尝试荣誉扩展组件的首选大小... 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(); } } } 和可运行的例子...... 这会达到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 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); } }); } 公共类TestPane扩展JPanel { 私人AccordionLayout布局; public TestPane(){ layout = new AccordionLayout(); setLayout(布局); AccordionListener listener = new AccordionListener(){ @Override public void accordionSelected(Component comp){ layout.setExpanded(comp); revalidate(); repaint(); } }; 颜色[] = {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); } } } 公共类ContentPane扩展JPanel { public ContentPane(Color background){ setBackground(background); } @Override public Dimension getPreferredSize(){ return new Dimension(100,100); } } 公共接口AccordionListener { public void accordionSelected(Component comp); } 公共类AccordionPanel扩展JPanel { 私人JLabel头衔; 私人JPanel标头; 私人组件内容; 私人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(字符串标题,组件内容){ 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; 返回大小; } } 公共类AccordionLayout实现LayoutManager { //这个可能受到约束的控制,但那样做假设 //可以一次扩展多个组件私有组件扩展; public void setExpanded(扩展组件){ 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; } 返回大小; } @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; } 返回新的尺寸(宽度,高度); } @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; //尝试荣誉扩展组件的首选大小... 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(); } } } } 现在,如果您真的想接受挑战,可以使用 So basically if I put JPanels inside a JPanel that uses GridBagLayout and I restrict the size with setPreferredSize, eventually it reaches a point where it can't hold all of them, and it exhibits the behavior shown in the attached picture:I'm making an accordion. This is just an example to showcase the problem I'm having. Each part of the accordion can open individually and they're of arbitrary size and get added on the fly. Its easy enough to get the heights of all the individual panels and compare them against the total height, but when too many are added it exhibits the crunching behavior I've shown. This also shrinks the heights so its much more difficult to determine when the crunching has happened. I would have to cache heights and somehow pre-calculate the heights of the new parts getting added. The end goal is to remove older panels when a new panel is added and there isn't enough room for it.Is there an easy way to determine what height something would be if it weren't constrained, or maybe a supported way to detect when such crunching has is happening (so I can quickly thin it out before it gets painted again)? An option that makes GridBagLayout behave like some other layouts and overflow into hammerspace instead of compressing would work too.Code for example: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(); } }); }}EDIT: Seems I didn't describe my version of the accordion very well. Here's a link. 解决方案 You have particular requirement which may be better served through the use of it's layout manager. This provides you the ability to control every aspect of the layout without the need to resort to hacks or "work arounds" which never quite work or have bizarre side effectspublic 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(); } }}And the runnable example...This goes to the enth degree, creating a specialised component to act as each "fold", but this just reduces the complexity of the API from the outside, meaning, you just need to think about the title and the content and let the rest of the API take care of itselfimport 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(); } } }}Now, if you're really up for a challenge, you could use something a animated layout proxy and do something like... 这篇关于JPanel中的JPanel太多(使用GridBagLayout)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云! 08-05 16:18