2011-11-26 97 views
5

我有一個JFrameCardLayout包含一組JPanels。每個JPanel具有不同的尺寸,我希望JFrame適應當前顯示的尺寸JPanel(而不是JPanel以適應JFrame的尺寸)。如何設置JFrame大小以適應CardLayout顯示的JPanel?

我該如何做到這一點?

+2

*「我希望JFrame適應當前顯示的JPanel的大小」*僅僅因爲顯示的內容發生變化而讓用戶改變幀大小會感到很奇怪。 –

+0

當內部面板不匹配時,修復大小JFrame非常難看。我嘗試過這個。 – JVerstry

+0

我不確定這會工作,但你可以試試這個:'frame.setSize(panel。getPreferredSize());' –

回答

11

一般是:如果你有一個佈局問題,總是用適當的佈局管理解決它。 從不調整組件的大小提示以達到您的目標。

在這種情況下,調整CardLayout特別容易。默認情況下,它會將其prefSize計算爲所有卡片的prefSizes的最大值。簡單地繼承並實現返回當前的可見卡片的prefSize(加插圖):

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); 
} 
+0

謝謝。這更乾淨,正是我想要的。 – JVerstry

+0

現在是世界上一個更清晰和美麗+1 – mKorbel

+0

所以乾淨,我不能相信它。謝謝! –

2

我覺得你可能有錯誤的佈局管理器來做你想做的事(暫時擱置一會兒,我不確定你是否想做你說的你想做的事)。

我還沒有找到有關我懷疑的文檔,即CardLayout將其所有子級調整爲其容器大小。我沒有找到它的「layoutContainer」方法如下評論:

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

我認爲這是合理的行爲,因爲那將是非常惱人的用戶具有面板尺寸跳圍繞面板運行。

如果這真的是你想要的行爲,那麼我認爲你想要一個不同的佈局管理器。而且,由於這是一般用戶界面的不尋常行爲,因此您可能找不到標準的用戶來執行此特定「功能」,因此您可能需要編寫自己的「功能」。

4

這是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(); 
      } 
     }); 
    } 
} 
+0

-1是否過度使用setPrefSize:一般規則(正如您所知道的:-)通過使用適當的LayoutManager來解決大小問題。如果你沒有找到你想要的東西,那麼編寫/調整一個LayoutManager ... – kleopatra

0
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); 
}}