2016-03-03 50 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