2012-01-09 16 views
14

Estoy aprendiendo a usar Swing y me encontré con una tarea bastante difícil.Panel superpuesto (arriba de otro)

Lo que intento lograr: quiero tener el panel (llámelo menú) en el lado izquierdo (digamos 100px de ancho) y el segundo panel (llámelo panel de contenido), que toma el resto del lugar disponible .

En el panel del menú hay 3 botones. Cuando presiono sobre ellos, en el lado derecho del panel de menú (sobre el panel de contenido) debe aparecer el segundo panel de menú (submenú) (y debería comenzar en el medio del botón que se presionó).

Puede ser difícil de entender, por lo que he creado proyecto simple:

enter image description here

me trataron JLayeredPane pero hubo problemas con el redimensionamiento (elementos de panel Capas no cambian de tamaño).

+0

Puede probar una subclase de JPopupMenu. Además, examine el código fuente de JComboBox y vea cómo usan el menú emergente allí. – Mitch

Respuesta

4

JLayeredPane implementaciones fallida de LayoutManager, que tienen que setPreferredSize o setBounds manualmente para determinar el tamaño/lugar JComponents,

hay una posible solución puede agregar ComponentListener a la JFrame, a continuación, en componentResized(ComponentEvent e) puede cambiar el tamaño/reemplazar JComponent(s) a el deseado Bounds

por ejemplo

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

Wow. Esto funciona muy bien. Pero tengo una pregunta. Por qué en esta línea textPanel.setSize (w, h); ¿configura la altura del panel de texto como altura del cuadro? Y textPanel no es la altura de las pantallas (su altura sigue siendo la misma). – pavel

+0

hay sobre JComponents de relleno al JFrame, puede jugar con Insets mediante uSng setSize/setBounds puede establecer las ubicaciones de tamaño deseado/esperado en relación con el padre – mKorbel

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

¿Qué sucede si estoy usando ie. GroupLayout en contentPanel? Estaba pensando en hacer este submenú como panel adicional sobre todo lo demás. – pavel

+0

Luego tenga dos paneles en capas en el panel de contenido, el que se encuentra arriba para el menú. –

2

Puede establecer un administrador de disposición para el panel en capas, javax.swing.OverlayLayout utiliza el espacio disponible completo y permite cambiar el tamaño.

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

Probablemente no desee que el submenú ocupe el espacio completo. Para evitarlo, puede anular sus métodos get ... size. O puede agregar un segundo LayeredPane (por su transparencia y su layoutmanager), establecer un BoxLayout normal y usar un espaciador.

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

El JLayeredPane obras de defualt sin controlador de distribución, lo que significa que está utilizando posicionamiento absoluto y sin cambio de tamaño. Puede agregar un oyente de cambio de tamaño y ajustar las posiciones y el tamaño de los componentes internos del código, como mejor le parezca.

Si no desea hacer esto desde el código, necesitará un administrador de diseño, nada especial, solo algo para llenar el contenedor a medida que cambia de tamaño. Pero aquí está la cosa ... si agrega un administrador de diseño, distribuirá los componentes como si estuvieran todos en una capa, pero la mayoría de los administradores de diseño no se superponen a sus hijos, por lo que son inútiles. El único que podría usar es OverlayLayout, también puede cambiar el tamaño de los niños. Pero usar OverlayLayout con JLayeredPane es excesivo. Puedes usar OverlayLayout con un JPanel. Entonces, sí, JLayeredPane es inútil. Recomiendo usar un JPanel con un OverlayLayout en su lugar.

He aquí cómo configurar las cosas para que pueda tener un gran control sobre casi cualquier escenario de UI superpuesto: usando un JPanel con OverlayLayout, tenga un JPanel transparente separado para cada capa. De esta forma, puede combinar varios Administradores de diseño en diferentes capas, configurando un administrador de diseño diferente para cada panel, incluido el posicionamiento absoluto si es necesario. Luego agregue sus componentes visibles dentro de los paneles que representan las capas. No los agregue directamente al panel OverlayLayout.Solo asegúrese de que todos los JPanels que está utilizando como capas tengan setAlignmentX e Y al centro (0.5f) para que llenen todo el panel OverlayLayout a medida que cambia de tamaño.

Cuestiones relacionadas