Подтвердить что ты не робот

Панель наложения (над другой)

Я изучаю, как использовать Swing и нашел себе довольно трудную задачу.

То, что я пытаюсь выполнить: хочу иметь панель (назовите ее панель меню) с левой стороны (допустим ширину 100 пикселей) и вторую панель (назовите ее панель содержимого), которая занимает остальную часть доступного места.

В панели меню есть 3 кнопки. Когда я нажимаю на них, в правой части панели меню (над панелью содержимого) появляется вторая панель меню (подменю) (и она должна начинаться в середине нажатой кнопки).

Это может быть трудно понять, поэтому я создал простой черновик:

enter image description here

Я попробовал JLayeredPane, но были проблемы с изменением размера окна (элементы в Layered Pane не изменялись).

4b9b3361

Ответ 1

JLayeredPane Пропускные возможности для LayoutManager, вы должны setPreferredSize или setBounds вручную для определения размера/места JComponents,

есть одно возможное обходное решение, которое вы можете добавить ComponentListener в JFrame, затем на 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();
            }
        });
    }
}

Ответ 2

Вы можете установить layoutmanager для многоуровневой панели javax.swing.OverlayLayout использует полное доступное пространство и позволяет изменять размер.

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

Вероятно, вы не хотите, чтобы подменю занимало полный пробел. Чтобы избежать этого, вы можете переопределить методы get... size-methods. Или вы можете добавить вторую LayeredPane (для нее трансплантированность и ее layoutmanager), установить нормальный BoxLayout и использовать разделитель.

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());

Ответ 3

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);
        }
    });
 }

Ответ 4

JLayeredPane работает defualt без менеджера макета, что означает, что вы используете абсолютное позиционирование и не изменяете размер. Вы можете добавить слушателя изменения размера и отрегулировать позиции и размер внутренних компонентов из кода, как вы сочтете нужным.

Если вы не хотите делать это из кода, вам понадобится менеджер компоновки, ничего необычного, просто что-то, чтобы заполнить контейнер по мере его изменения. Но вот что... если вы добавите диспетчер макетов, он будет компоновать компоненты, как если бы они были на одном уровне, но большинство менеджеров макетов не перекрывают своих детей, поэтому они бесполезны. Единственный, который вы можете использовать, это OverlayLayout - он также может изменять размер детей. Но использование OverlayLayout с JLayeredPane является излишним. Вы можете просто использовать OverlayLayout с JPanel. Итак, да, JLayeredPane бесполезен. Я рекомендую использовать JPanel вместо OverlayLayout.

Вот как это можно настроить, чтобы вы могли отлично управлять практически любым перекрывающимся сценарием пользовательского интерфейса: используя JPanel с OverlayLayout, для каждого слоя есть отдельный прозрачный JPanel. Таким образом, вы можете комбинировать различные LayoutManager на разных уровнях, устанавливая для каждого окна другой менеджер компоновки, включая, при необходимости, абсолютное позиционирование. Затем добавьте видимые компоненты внутри панелей, представляющих слои. Не добавляйте их непосредственно на панель OverlayLayout. Просто убедитесь, что все JPanels, которые вы используете в качестве слоев, имеют setAlignmentX и Y в центр (0.5f), чтобы они заполнили всю панель OverlayLayout по мере ее изменения.