如何设置JFrame大小以适合显示JPanel的CardLayout?

我在CardLayout中有一个包含一组JPanelsJFrame 。 每个JPanel都有不同的大小,我希望JFrame适应当前显示的JPanel的大小(而不是JPanel以适应JFrame的大小)。

我怎样才能做到这一点?

一般是:如果您有布局问题,请始终使用适当的LayoutManager解决它。 永远不要调整组件的大小提示来达到目标​​。

在这种情况下,调整CardLayout特别容易。 默认情况下,它会将prefSize计算为所有卡的prefSizes的最大值。 简单地子类化并实现以返回当前可见卡的prefSize(加上insets):

 public static class MyCardLayout extends CardLayout { @Override public Dimension preferredLayoutSize(Container parent) { Component current = findCurrentComponent(parent); if (current != null) { Insets insets = parent.getInsets(); Dimension pref = current.getPreferredSize(); pref.width += insets.left + insets.right; pref.height += insets.top + insets.bottom; return pref; } return super.preferredLayoutSize(parent); } public Component findCurrentComponent(Container parent) { for (Component comp : parent.getComponents()) { if (comp.isVisible()) { return comp; } } return null; } } 

使用它(借用@ mKorbel的例子),主要方法干净利落:

 private static void createAndShowUI() { final CardLayout cardLayout = new MyCardLayout(); final JPanel cardHolder = new JPanel(cardLayout); final JFrame frame = new JFrame("MultiSizedPanels"); JLabel[] labels = { new JLabel("Small Label", SwingConstants.CENTER), new JLabel("Medium Label", SwingConstants.CENTER), new JLabel("Large Label", SwingConstants.CENTER)}; for (int i = 0; i < labels.length; i++) { int padding = 50 * (i + 1); Border lineBorder = BorderFactory.createCompoundBorder( BorderFactory.createLineBorder(Color.blue), BorderFactory.createEmptyBorder(padding, padding, padding, padding)); labels[i].setBorder(lineBorder); JPanel containerPanel = new JPanel(); containerPanel.add(labels[i]); cardHolder.add(containerPanel, String.valueOf(i)); } JButton nextButton = new JButton("Next"); nextButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { cardLayout.next(cardHolder); frame.pack(); } }); JPanel btnHolder = new JPanel(); btnHolder.add(nextButton); frame.add(cardHolder, BorderLayout.CENTER); frame.add(btnHolder, BorderLayout.SOUTH); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setLocation(150, 150); frame.setVisible(true); } 

这是SSCCE 。

1)为了持续增加/减少大小,你应该寻找一些动画API。

要么

2)如果没有任何后台任务输出到GUI,您可以在调整JFrame大小时暂停。 在这种情况下,您可以通过使用包装到Runnable线程中的Thread#sleep(int)来延迟增加/减少。

3)在EDT期间直接使用Thread#sleep(int) )的注意事项(不适用于OP)将冻结GUI直到延迟结束。

 import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.Border; //based on HFOE http://stackoverflow.com/questions/5414177/change-size-of-jpanel-using-cardlayout/5414770#5414770 public class MultiSizedPanels { private static void createAndShowUI() { final CardLayout cardLayout = new CardLayout(); final JPanel cardHolder = new JPanel(cardLayout); final JFrame frame = new JFrame("MultiSizedPanels"); JLabel[] labels = { new JLabel("Small Label", SwingConstants.CENTER), new JLabel("Medium Label", SwingConstants.CENTER), new JLabel("Large Label", SwingConstants.CENTER)}; for (int i = 0; i < labels.length; i++) { int padding = 50; Dimension size = labels[i].getPreferredSize(); size = new Dimension(size.width + 2 * (i + 1) * padding, size.height + 2 * (i + 1) * padding); labels[i].setPreferredSize(size); Border lineBorder = BorderFactory.createLineBorder(Color.blue); labels[i].setBorder(lineBorder); JPanel containerPanel = new JPanel(); if (i == 1) { containerPanel.setPreferredSize(new Dimension(300, 200)); containerPanel.add(labels[i], BorderLayout.CENTER); cardHolder.add(containerPanel, String.valueOf(i)); } else if (i == 2) { containerPanel.setPreferredSize(new Dimension(600, 400)); containerPanel.add(labels[i], BorderLayout.CENTER); cardHolder.add(containerPanel, String.valueOf(i)); } else { containerPanel.setPreferredSize(new Dimension(800, 600)); containerPanel.add(labels[i], BorderLayout.CENTER); cardHolder.add(containerPanel, String.valueOf(i)); } } JButton nextButton = new JButton("Next"); nextButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { cardLayout.next(cardHolder); Dimension dim = new Dimension(); for (Component comp : cardHolder.getComponents()) { if (comp.isVisible() == true) { dim = comp.getPreferredSize(); } } frame.setPreferredSize(dim); java.awt.EventQueue.invokeLater(new Runnable() { public void run() { frame.pack(); } }); } }); JPanel btnHolder = new JPanel(); btnHolder.add(nextButton); frame.add(cardHolder, BorderLayout.CENTER); frame.add(btnHolder, BorderLayout.SOUTH); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setLocation(150, 150); frame.setVisible(true); } public static void main(String[] args) { java.awt.EventQueue.invokeLater(new Runnable() { public void run() { createAndShowUI(); } }); } } 

我想你可能有一个错误的布局经理你想做什么(暂时不说,暂时,我不确定你想做你想做的事)。

我还没有找到我怀疑的文档,也就是CardLayout将其所有子节点调整到其容器大小。 我确实为其“layoutContainer”方法找到了以下注释:

  * Each component in the parent container is reshaped * to be the size of the container, minus space for surrounding * insets, horizontal gaps, and vertical gaps. 

我认为这是合理的行为,因为当遍历面板时,用户让面板大小跳跃会非常烦人。

如果这确实是你想要的行为,那么我认为你想要一个不同的布局管理器。 而且由于这对于一般用户界面来说是不寻常的行为,你可能找不到一个标准的用于执行这个特定的“function”,所以你可能必须自己编写。

 Try this code this may help you. protected void paintComponent(Graphics g) { if (getModel().isArmed()) { g.setColor(Color.lightGray); } else { g.setColor(getBackground()); } g.fillOval(0, 0, getSize().width-1, getSize().height-1); System.out.println("width is "+getSize().width+"height is "+getSize().height); super.paintComponent(g); } protected void paintBorder(Graphics g) { g.setColor(getForeground()); g.drawOval(0, 0, getSize().width-1, getSize().height-1); } Shape shape; public boolean contains(int x, int y) { if (shape == null || !shape.getBounds().equals(getBounds())) { shape = new Ellipse2D.Float(0, 0, getWidth(), getHeight()); } return shape.contains(x, y); }}