Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overlay panel (above another)

Tags:

java

swing

I am learning how to use Swing and found myself quite difficult task.

What I am trying to accomplish: I want to have panel (call it menu panel) on the left side (let's say 100px width) and the second panel (call it content panel), which takes the rest of available place.

In menu panel there are 3 buttons. When I press on of them, to the right side of menu panel (over content panel) second menu panel (submenu) should appear (and it should start in the middle of button which was pressed).

It may be hard to understand, so I've created simple draft:

enter image description here

I tried JLayeredPane but there were problems with resizing window (elements in Layered Pane didn't resize).

like image 374
pavel Avatar asked Jan 09 '12 16:01

pavel


3 Answers

JLayeredPane miss implementations for LayoutManager, you have to setPreferredSize or setBounds manually for sizing/place JComponents,

there is one possible workaround you can add ComponentListener to the JFrame, then on componentResized(ComponentEvent e) you can resize/replace JComponent(s) to the desired Bounds

for example

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();
            }
        });
    }
}
like image 72
mKorbel Avatar answered Nov 19 '22 14:11

mKorbel


You can set a layoutmanager for the layered pane, javax.swing.OverlayLayout uses the full available space and allows resizing.

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

You probably don't want the submenu to occupy the fullspace. To avoid it you can override its get…size-methods. Or you can add a second LayeredPane (for it's transperancy and it's layoutmanager), set a normal BoxLayout and use a 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());
like image 3
Kasper van den Berg Avatar answered Nov 19 '22 14:11

Kasper van den Berg


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);
        }
    });
 }
like image 1
Joop Eggen Avatar answered Nov 19 '22 15:11

Joop Eggen