[英]Jpanels with Gridbaglayout inside a JPanel with GridbagLayout problems
[英]Too many JPanels inside a JPanel (with GridBagLayout)
所以基本上如果我把JPanel
放在一个使用GridBagLayout
的JPanel
,我用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();
}
});
}
}
编辑:似乎我没有很好地描述我的手风琴版本。 这是一个链接 。
您有特殊的要求,通过使用它的布局管理器可以更好地服务。 这使您能够控制布局的各个方面,而无需诉诸黑客或“解决方法”,这些工作从未完全奏效或具有奇怪的副作用
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();
}
}
}
可运行的例子......
这就是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();
}
}
}
}
现在,如果你真的想要挑战,你可以使用一些动画布局代理,并做一些像...
最终目标是在添加新面板并且没有足够空间时移除旧面板
我猜想在添加一个面板后,你可以将首选高度与实际高度进行比较。 当首选高度较大时,您遇到问题,并根据需要删除组件。
那么接下来的问题是使用不改变面板高度的布局管理器。 这仍然可以通过GridBagLayout完成。 您只需要覆盖getMinimumSize()
方法以返回getPreferredSize()
维度。
手风琴的每个部分都可以单独打开,它们具有任意大小,可以随时添加
您可能需要考虑使用相对布局 。 您可以添加其首选大小将受到尊重的组件。 因此,您可以检查首选高度何时大于实际高度。
然后,您还可以添加将根据面板中剩余的空间量调整大小的组件。 这些将是你的扩展面板。
因此,在您的示例中,您展示项目时的示例可以将该组件配置为占用整个可用空间。 如果展开两个项目,那么每个项目将获得一半的可用空间。
也许是这样的:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ExpandingPanel extends JPanel
{
private JPanel expanding;
public ExpandingPanel(String text, Color color)
{
setLayout( new BorderLayout() );
JButton button = new JButton( text );
add(button, BorderLayout.NORTH);
expanding = new JPanel();
expanding.setBackground( color );
expanding.setVisible( false );
add(expanding, BorderLayout.CENTER);
button.addActionListener( new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
expanding.setVisible( !expanding.isVisible() );
Container parent = ExpandingPanel.this.getParent();
LayoutManager2 layout = (LayoutManager2)parent.getLayout();
if (expanding.isVisible())
layout.addLayoutComponent(ExpandingPanel.this, new Float(1));
else
layout.addLayoutComponent(ExpandingPanel.this, null);
revalidate();
repaint();
}
});
}
private static void createAndShowGUI()
{
RelativeLayout rl = new RelativeLayout(RelativeLayout.Y_AXIS);
rl.setFill( true );
JPanel content = new JPanel( rl );
content.add( new ExpandingPanel("Red", Color.RED) );
content.add( new ExpandingPanel("Blue", Color.BLUE) );
content.add( new ExpandingPanel("Green", Color.GREEN) );
JFrame frame = new JFrame("Expanding Panel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( content);
frame.setLocationByPlatform( true );
frame.setSize(200, 300);
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}
当panel.getPreferredSize().height != panel.getHeight()
和panel.getPreferredSize().width != panel.getWidth()
时,你可以告诉某事是“嘎吱嘎吱”的panel.getPreferredSize().height != panel.getHeight()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.