2012-01-09 111 views
14

我正在学习如何使用Swing,并发现自己相当困难的任务。覆盖面板(上面的另一个)

我想要实现的是:我想让左侧的面板(称为菜单面板)(假设为100像素宽度)和第二个面板(称为内容面板),这需要剩下的可用空间。

在菜单面板上有3个按钮。当我按下它们时,在菜单面板的右侧(在内容面板上),应该出现第二个菜单面板(子菜单)(它应该在按下的按钮的中间开始)。

这可能是很难理解,所以我创建了简单的草案:

enter image description here

我试过的JLayeredPane但也有与调整窗口的问题(在分层窗格元素没有调整)。

+0

你可以试试JPopupMenu的一个子类。另外,请检查JComboBox的源代码并查看它们如何使用弹出式菜单。 – Mitch 2012-01-09 17:18:39

回答

4

JLayeredPane错过实现了LayoutManager,你必须setPreferredSize或手动setBounds用于上浆/地方JComponents

有一个可能的解决方法,你可以添加ComponentListenerJFrame,然后componentResized(ComponentEvent e)你可以调整/替换JComponent(s)到所需Bounds

例如

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

public class LayeredPaneWithOverlap { 

    private JTextArea textArea = new JTextArea(2, 10); 
    private JPanel textPanel = new JPanel(new BorderLayout()); 
    private JTable table = new JTable(30, 5); 
    private JScrollPane scroll = new JScrollPane(table); 
    private JLayeredPane layer = new JLayeredPane(); 
    private JFrame frame = new JFrame("Frame with resiziable JLayeredPane"); 

    public void makeUI() { 
     textArea.setBorder(new LineBorder(Color.DARK_GRAY)); 
     textArea.setText("Frame with resiziable JLayeredPane"); 
     textPanel.setOpaque(false); 
     textPanel.add(textArea, BorderLayout.NORTH); 
     Font font = textArea.getFont(); 
     FontMetrics fontMetrics = textArea.getFontMetrics(font); 
     int h = fontMetrics.getHeight() + frame.getInsets().top + 
       textPanel.getInsets().top + textArea.getInsets().top 
       + textArea.getInsets().bottom; 
     scroll.setBounds(0, h, 400, 300); 
     layer.add(textPanel, new Integer(2)); 
     layer.add(scroll, new Integer(1)); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setSize(600, 400); 
     frame.addComponentListener(new ComponentAdapter() { 

      @Override 
      public void componentResized(ComponentEvent e) { 

       SwingUtilities.invokeLater(new Runnable() { 

        @Override 
        public void run() { 
         resizeAll(); 
        } 
       }); 
      } 
     }); 
     frame.setLocationRelativeTo(null); 
     frame.add(layer); 
     resizeAll(); 
     frame.setVisible(true); 
    } 

    void resizeAll() { 
     Insets insets = frame.getInsets(); 
     int w = frame.getWidth() - insets.left - insets.right; 
     int h = frame.getHeight() - insets.top - insets.bottom; 
     textPanel.setSize(w, h); 
     scroll.setSize(w, h - scroll.getY()); 
     layer.revalidate(); 
     layer.repaint(); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       new LayeredPaneWithOverlap().makeUI(); 
      } 
     }); 
    } 
} 
+0

哇。这工作非常好。但我有一个问题。为什么在这一行textPanel.setSize(w,h);你是否将textPanel高度设置为框架高度?而textPanel不是屏幕高度(它的高度保持不变)。 – pavel 2012-01-10 07:41:01

+0

有关于填充JComponent的JComponents,你可以通过uisng使用Insets播放setSize/setBounds,你可以设置期望/预期的大小相对于父项的位置 – mKorbel 2012-01-10 08:31:55

1
contentPanel.setLayout(null); // Absolute positioning of children. 

@Override 
public void actionPerformed(ActionEvent evt) { 
    final JButton btn = (JButton) evt.getSource(); 
    final int buttonY = btn.getY(); // Must be final for usage in new Runnable object. 

    SwingUtilities.invokeLater(new Runnable() { // Return fast from event handling. 

     @Override 
     public void run() { 
      JPanel child = new JPanel(); 
      child.setBackground(Color.RED); // So we'll see it. 
      child.setBounds(0, buttonY, 100, 300); 
      contentPanel.removeAll(); // Clear content panel of prior additions. 
      contentPanel.add(child); // Add a new panel. 
      contentPanel.repaint(10L); 
     } 
    }); 
} 
+0

如果我使用ie。 contentPanel中的GroupLayout?我正在考虑把这个子菜单作为额外的面板,超过所有其他的东西。 – pavel 2012-01-09 17:48:31

+0

然后在contentPanel中有两个分层窗格,上面的窗格为菜单提供服务。 – 2012-01-09 18:02:28

2

您可以为分层窗格设置布局管理器,javax.swing.OverlayLayout使用完整的可用空间并允许调整大小。

JLayeredPane layer = new JLayeredPane(); 
layer.setLayout(new OverlayLayout(layer)); 

您可能不希望子菜单占据fullspace。为了避免它,你可以重写它的get ... size-methods。或者你可以添加第二个LayeredPane(因为它是transperancy,它是layoutmanager),设置一个普通的BoxLayout并使用一个spacer。

JPanel normalContents = new JPanel(); 
layer.add(normalContents, JLayeredPane.DEFAULT_LAYER); 
JLayeredPane subMenuAuxiliaryLayer = new JLayeredPane() 
subMenuAuxiliaryLayer.setLayout(new BoxLayout(subMenuAuxiliaryLayer, BoxLayout.LINE_AXIS)); 
layer.add(subMenuAuxiliaryLayer, JLayeredPane.PALETTE_LAYER); 
JPanel submenuContents = new JPanel(); 
subMenuAuliliaryLayer.add(submenuContents); 
subMenuAuxiliaryLayer.add(Box.createHorizontalGlue()); 
0

JLayeredPane的工作原理是没有布局管理器,这意味着你正在使用绝对定位和不调整大小。如果您认为合适,您可以添加一个调整大小的侦听器,并根据代码调整内部组件的位置和大小。

如果你不想从代码中做到这一点,你将需要一个布局管理器,没什么特别的,只是在调整大小时填充容器。但是,事情就是......如果添加一个布局管理器,它会将组件布置成好像它们全都在一个图层中一样,但是大多数布局管理器不会重叠它们的子组件,因此它们是无用的。唯一可以使用的是OverlayLayout - 它也可以调整儿童的大小。但与JLayeredPane一起使用OverlayLayout是矫枉过正的。你可以使用OverlayLayout和JPanel。所以,是的,JLayeredPane是没用的。我建议使用带OverlayLayout的JPanel。

以下是设置方法,以便您可以很好地控制几乎所有重叠的UI场景:使用具有OverlayLayout的JPanel,为每个图层都有单独的透明JPanel。通过这种方式,您可以通过为每个窗格设置不同的布局管理器来在不同的图层上组合各种布局管理器,包括必要时的绝对定位。然后在代表图层的面板中添加可见组件。不要直接将它们添加到OverlayLayout面板。只要确保您用作图层的所有JPanel都将setAlignmentX和Y设置为居中(0.5f),以便它们在调整大小时填充整个OverlayLayout面板。