2015-05-20 31 views
3

以下是將兩個面板添加到一個框架的示例。只出現一個面板(第二個,紅色面板)。爲什麼添加到框架的第一個面板消失了?

Disappearing Panel In Frame

爲什麼第一個面板中消失?

import java.awt.*; 
import javax.swing.*; 
import javax.swing.border.EmptyBorder; 

public class DisappearingPanelInFrame { 

    DisappearingPanelInFrame() { 
     JFrame f = new JFrame(this.getClass().getSimpleName()); 
     f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 

     f.add(new ColoredPanel(Color.GREEN)); 
     f.add(new ColoredPanel(Color.RED)); 

     f.pack(); 
     f.setVisible(true); 
    } 

    public static void main(String[] args) { 
     Runnable r = new Runnable() { 
      @Override 
      public void run() { 
       new DisappearingPanelInFrame(); 
      } 
     }; 
     SwingUtilities.invokeLater(r); 
    } 
} 

class ColoredPanel extends JPanel { 

    ColoredPanel(Color color) { 
     setBackground(color); 
     setBorder(new EmptyBorder(20, 150, 20, 150)); 
    } 
} 
+1

絕對是一個[自我價值的FAQ](http://meta.stackoverflow.com/q/17463/163188);使用「Border」來實現特定的初始大小的榮譽;當你擴展'JPanel'時,也考慮覆蓋['getPreferredSize()'](http://stackoverflow.com/q/7229226/230513)。 – trashgod

+1

@trashgod是的。我確實考慮覆蓋'getPreferredSize()'而不是設置邊框(我也考慮過只是爲框架設置一個尺寸!)。我在兩種不同的方法之間玩弄。 1)在各方面使用最佳實踐。 2)使整個代碼示例出現在沒有垂直滾動條的單個代碼塊中。 - 在這種情況下,後者勝出(大部分)。 ;) –

回答

5
  • 一個JFrame的默認佈局(或更具體地在這種情況下,內容窗格中的幀的)是BorderLayout
  • 向沒有約束的BordeLayout添加組件時,Swing API會將組件放入CENTER
  • A BorderLayout可以精確包含一個組件在每個佈局約束中。
  • 當第二個組件被添加到BorderLayout的相同約束(在這種情況下爲CENTER)時,此Java實現將顯示最後添加的組件。

至於什麼是更好的方法取決於用戶界面的具體需求。

+0

這個答案將在兩天內(最可能)被接受。其他質量的答案可能會吸引賞金。 –

+1

我剛剛意識到你可能已經知道答案了,嘿。 – immibis

+0

@immibis是的。 :)在過去24小時內,我幾乎寫了這個答案作爲評論兩次,這讓我覺得值得創建一個可以用作重複的問答。 ;) –

3

當第二組件被添加到相同的(在這種情況下CENTER)一個BorderLayout的約束,這種實現的Java將顯示最後組分加入。

不完全正確。

BorderLayout只會將最後一個組件添加到特定約束位置的reset the bounds(即大小和位置)。這與其他佈局管理器不同,因爲它們將重置容器中所有組件的邊界。

在示例代碼中,當通過使用pack()方法驗證框架時,紅色面板是「活動」面板,因此僅設置了邊界,因此僅繪製邊框。

對於這個過程的示範運行下面使用以下步驟的例子:

  1. 單擊「添加面板中心」按鈕,雖然藍色面板添加到中央沒有出現,甚至發生。
  2. 將鼠標移動到紅色面板上,將出現按鈕,因爲鼠標滾動邏輯會導致重新繪製按鈕。
  3. 現在增加框架寬度,藍色面板將出現在紅色面板下。

的代碼:

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 
import javax.swing.border.EmptyBorder; 

public class DisappearingPanelInFrame { 

    DisappearingPanelInFrame() 
    { 

     JButton button = new JButton ("Add Panel In Center"); 
     button.addActionListener(new ActionListener() 
     { 
      @Override 
      public void actionPerformed(ActionEvent e) 
      { 
       JPanel blue = new JPanel(); 
       blue.setBackground(Color.BLUE); 
       blue.add(new JButton("Button 1")); 
       blue.add(new JButton("Button 2")); 

       Component c = (Component)e.getSource(); 
       Window window = SwingUtilities.windowForComponent(c); 
       window.add(blue); 
       window.revalidate(); 
       window.repaint(); 
      } 
     }); 

     JFrame f = new JFrame(this.getClass().getSimpleName()); 
     f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 

     f.add(new ColoredPanel(Color.GREEN)); 
     //f.pack(); 
     f.add(new ColoredPanel(Color.RED)); 
     f.add(button, BorderLayout.SOUTH); 

     f.pack(); 
     f.setVisible(true); 
    } 

    public static void main(String[] args) { 
     Runnable r = new Runnable() { 
      @Override 
      public void run() { 
       new DisappearingPanelInFrame(); 
      } 
     }; 
     SwingUtilities.invokeLater(r); 
    } 
} 

class ColoredPanel extends JPanel { 

    ColoredPanel(Color color) { 
     setBackground(color); 
     setBorder(new EmptyBorder(20, 150, 20, 150)); 
    } 
} 

當藍色面板添加到BorderLayout的,並且當revalidate()被調用藍色面板的邊界被設置。

但是,由於Swing的ZOrder繪畫方式,首先繪製藍色面板,然後將紅色面板繪製在藍色面板的頂部。綠色面板仍然具有(0,0)的大小,因爲當框架最初使用pack()方法進行驗證時,它從來不是BorderLayout.CENTER中的「活動」面板。

當幀的大小時,藍色面板是「活動」面板中BorderLayout.CENTER,有其範圍調整,所以現在將填補幀的額外空間。

現在對於另一個測試:

  1. pack()加入綠色面板至框架後的幀。
  2. 運行代碼並增加幀的寬度和紅色和綠色幀將出現
  3. 然後點擊按鈕和增加寬度,現在所有3個面板將出現

底線是仍然相同:

不要嘗試將多個面板添加到BorderLayout的相同約束。如果你這樣做,那麼確保你移除了前一個面板,否則你有可能發生意想不到的結果。

相關問題