2016-03-03 68 views
1

我試圖將一個JPanel放在另一個之上,完全重疊。 我使用JLayeredPane使它們處於不同的「深度」,因此我可以更改深度和不透明度,以便在另一個「下」看到某個面板。 這裏是一個小測試,我做了哪些工作正常:Java Swing:結合CardLayout和JLayeredPane的效果

public class LayeredCardPanel extends JPanel { 

     private static final String BLUE_PANEL  = "blue "; 
     private static final String RED_PANEL  = "red  "; 
     private static final String GREEN_PANEL = "green"; 

     private String[] panelNames = { BLUE_PANEL, RED_PANEL, GREEN_PANEL }; 
     private Color[] panelColors = { Color.BLUE, Color.RED, Color.GREEN }; 

     private List<JPanel> panels = new ArrayList<>(); 

     private final int TOP_POSITION = 30; 
     private static final int PANELS_FIRST_POS = 10; 

     private JLayeredPane layeredPane; 


     public LayeredCardPanel() { 

      setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); 

      add(createControlPanel()); 

      layeredPane = new JLayeredPane(); 

      //////////////////////////////////////////////////////////////// 
      //setting layout here results in all grey, non functioning panel. 
      //layeredPane.setLayout(new CardLayout(0, 0)); 
      ////////////////////////////////////////////////////////////// 

      add(layeredPane); 

      //adding 3 panel 
      for (int i = 0; i < panelNames.length; i++) { 

       JPanel panel = new JPanel(); 
       panel.setBackground(panelColors[i]); 

       layeredPane.add(panel); 
       layeredPane.setLayer(panel, PANELS_FIRST_POS + i); 

       panels.add(panel); 
      } 

      //////////////////////////////////////////////////////////// 
      //setting the card here, after adding panels, works fine 
      layeredPane.setLayout(new CardLayout(0, 0)); 
      ////////////////////////////////////////////////////////// 
     } 

測試結果如下:

,你可以在//////註釋行之間看到,這項測試工作正常,只有當我將CardLayout設置爲JLayeredPane我添加了JPanel s到它。 在我看來,使用默認佈局管理器將JPanel添加到JLayeredPane。佈局(設置和更改邊界以填充JLayeredPane)由稍後應用的CardLayout完成。

我的問題是:雖然這是工作,我需要的解決方案(使用一個佈局管理器添加,然後取代它來實現我想要的佈局)看起來不是一個優雅的解決方案。我正在尋找更好的方法來做到這一點。


這裏是整個SSCE:

public class LayeredCardPanel extends JPanel { 

     private static final String BLUE_PANEL  = "blue "; 
     private static final String RED_PANEL  = "red  "; 
     private static final String GREEN_PANEL = "green"; 

     private String[] panelNames = { BLUE_PANEL, RED_PANEL, GREEN_PANEL }; 
     private Color[] panelColors = { Color.BLUE, Color.RED, Color.GREEN }; 

     private List<JPanel> panels = new ArrayList<>(); 

     private final int TOP_POSITION = 30; 
     private static final int PANELS_FIRST_POS = 10; 

     private JLayeredPane layeredPane; 

     public LayeredCardPanel() { 

      setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); 

      add(createControlPanel()); 

      layeredPane = new JLayeredPane(); 

      add(layeredPane); 

      //add 3 panel 
      for (int i = 0; i < panelNames.length; i++) { 

       JPanel panel = new JPanel(); 
       panel.setBackground(panelColors[i]); 

       layeredPane.add(panel); 
       layeredPane.setLayer(panel, PANELS_FIRST_POS + i); 

       panels.add(panel); 
      } 

      layeredPane.setLayout(new CardLayout()); 
     } 

     private JPanel createControlPanel() { 

      ActionListener aListener = new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 

        if(e.getSource() instanceof JButton) { 

         moveToTop(((JButton) e.getSource()).getActionCommand()); 
        } 
       } 
      }; 

      JPanel controls = new JPanel(); 
      controls.setLayout(new BoxLayout(controls, BoxLayout.Y_AXIS)); 

      JButton blueViewBtn = new JButton(BLUE_PANEL); 
      blueViewBtn.setActionCommand(BLUE_PANEL); 
      blueViewBtn.addActionListener(aListener); 
      controls.add(blueViewBtn); 

      JButton redViewBtn = new JButton(RED_PANEL); 
      redViewBtn.setActionCommand(RED_PANEL); 
      redViewBtn.addActionListener(aListener); 
      controls.add(redViewBtn); 

      JButton greenViewBtn = new JButton(GREEN_PANEL); 
      greenViewBtn.setActionCommand(GREEN_PANEL); 
      greenViewBtn.addActionListener(aListener); 
      controls.add(greenViewBtn); 

      return controls; 
     } 

     private void moveToTop(String panelName) { 

      for(int i = 0; i < panelNames.length; i++) { 

       if(panelNames[i].equals(panelName)) { 
        layeredPane.setLayer(panels.get(i),TOP_POSITION); 
       } else { 
        layeredPane.setLayer(panels.get(i), PANELS_FIRST_POS + i); 
       } 
      } 
     } 

     public static void main(String[] args) { 

      javax.swing.SwingUtilities.invokeLater(new Runnable() { 
       @Override 
       public void run() { 

        JFrame frame = new JFrame("Layered Card Panel Simulation"); 
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

        JComponent newContentPane = new LayeredCardPanel(); 
        newContentPane.setPreferredSize(new Dimension(300,100)); 
        frame.setContentPane(newContentPane); 

        frame.pack(); 
        frame.setVisible(true); 
       } 
      }); 
     } 
    } 
+0

'你可以見' - 不,我們不能看到,因爲你的代碼不可執行。發佈適當的[SSCCE](http://sscce.org/),可以在發佈代碼時證明問題。 – camickr

+0

「正如你可以在//////之間看到的那樣:是的,你可以看到它。它在代碼中。我加載了最小的代碼來演示問題。 SSCE要長得多。 – c0der

回答

0

我應用的解決方案如下:我改變了承辦如此的layeredPane使用自定義佈局管理器Layout()

 public LayeredCardPanel() { 

      setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); 
      add(createControlPanel()); 

      layeredPane = new JLayeredPane(); 
      layeredPane.setLayout(new Layout()); 
      add(layeredPane); 

      //add 3 panel 
      for (int i = 0; i < panelNames.length; i++) { 

       JPanel panel = new JPanel(); 
       panel.setBackground(panelColors[i]); 

       layeredPane.add(panel); 
       layeredPane.setLayer(panel, PANELS_FIRST_POS + i); 

       panels.add(panel); 
      } 
     } 

Layout()延伸CardLayout覆蓋addLayoutComponent什麼都不做:

class Layout extends CardLayout{ 

     @Override 
     public void addLayoutComponent(String name, Component comp) { 
      // override to do nothing 
     } 
    } 
2

基本上你不使用CardLayout。即使您沒有setLayout(...)聲明,您的代碼也可以正常工作。

當您使用CardLayout:

  1. 佈局管理器只能跟蹤已設置的佈局管理器後添加的卡。
  2. 只有一個組件在時間顯示過,你不想因爲要與面板的透明度

編輯播放:

當您設置CardLayout後面板被添加到它們不是由CardLayout處理的分層窗格。結果所有面板都保持可見。顯然,所有這一切發生的是,CardLayout將設置每個面板的大小以填充可用空間,以使繪畫看起來正常工作。

當我修改您的SSCCE設置CardLayout之前添加面板,然後CardLayout管理面板。所以CardLayout在所有面板上調用setVisible(false),除了添加的第一個面板外,其中SSCCE是藍色面板。所以即使您嘗試將不同的面板移動到前面,您也只會看到藍色面板。

layeredPane.setLayer(panel, PANELS_FIRST_POS + i); 
System.out.println(panel.isVisible()); 

所以,是的,使用CardLayout是一個真正的黑客,是不是CardLayout意欲使用的方式或JLayeredPane的方式:

這很容易由以下更改SSCCE驗證打算使用。

JLayeredPane實際上意味着與空佈局一起使用,這意味着您負責設置每個組件的大小。爲了更好的解決方案,我建議您需要將ComponentListener添加到分層窗格。那麼你應該處理componentResized(...)事件。然後,您將遍歷添加到分層窗格的所有組件,並將每個組件的大小設置爲等於分層窗格的大小。

+0

謝謝@camickr。我也認爲代碼在沒有setLayout(...)總線的情況下工作不會。它顯示灰色內容窗格。另外:可以在卡片佈局中使用透明卡片。 – c0der

+0

@OferYuval,基於SSCCE,我做了一個編輯,其中包含對正在發生的事情和可能的解決方案的更好描述。 「可以在卡片佈局中使用透明卡片。」 - 當然,一次只能看到一張卡片,因此您不會將多張透明卡片的效果疊加在一起。 – camickr

+0

謝謝@camickr爲解釋發生了什麼的詳細答案。我將在這裏發佈另一個基於將Cardlayout的子類應用於llayeredPane的解決方案。 P.S:使用CardLayout可以「將多張透明卡片的效果疊加在一起」。 – c0der