Почему моя JPanel перегружает JFrame?

Я относительно новичок в программировании, поэтому извините, если этот вопрос глупый. Я создаю программу Java, которая включает одну кнопку JButton внутри JPanel, а JPanel находится в JFrame. Другая кнопка находится за пределами JPanel, но все еще находится в JFrame. Я установил макет на BoxLayout. Моя проблема в том, что панель, которую я сделал черной, занимает весь JFrame, за исключением того места, где находится вторая кнопка. Как сделать так, чтобы JPanel занимала только область вокруг первой кнопки?

public class alt {
    JFrame frame = new JFrame();
    JPanel panel = new JPanel();
    JButton button1 = new JButton("button 1");
    JButton button2 = new JButton("button 2");
    public alt(){
        frame.setVisible(true);
        frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS));
        panel.setBackground(Color.black);
        frame.setTitle("test");
        frame.setExtendedState(java.awt.Frame.MAXIMIZED_BOTH);
        panel.add(button1);
        frame.add(panel);
        frame.add(button2);
        button2.setAlignmentX(Component.CENTER_ALIGNMENT);
    }
}

person Benjy68    schedule 05.08.2014    source источник
comment
Используйте другой менеджер компоновки, например, GridBagLayout. Дополнительные сведения см. в разделе Размещение компонентов внутри контейнера. подробности   -  person MadProgrammer    schedule 05.08.2014
comment
@MadProgrammer попробую, спасибо за ответ!   -  person Benjy68    schedule 05.08.2014


Ответы (2)


Вы можете использовать другой менеджер компоновки, который дает вам больше контроля над распределением пространства и обработкой заполнения, например, GridBagLayout...

Пример

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class SampleLayout {

    public static void main(String[] args) {
        new SampleLayout();
    }

    public SampleLayout() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JPanel panel = new JPanel();
                JButton button1 = new JButton("button 1");
                JButton button2 = new JButton("button 2");

                panel.setBackground(Color.black);
                panel.add(button1);

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new GridBagLayout());
                GridBagConstraints gbc = new GridBagConstraints();
                gbc.gridwidth = GridBagConstraints.REMAINDER;
                frame.add(panel, gbc);
                frame.add(button2, gbc);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

}

Дополнительные сведения см. в разделе Размещение компонентов внутри контейнера. подробности

person MadProgrammer    schedule 05.08.2014

Причина, по которой ваша панель занимает большую часть панели содержимого фрейма, заключается в том, как менеджер BoxLayout работает с минимальными, предпочтительными и максимальными значениями компонентов. При этом учитывается максимальное значение компонента. А поскольку максимальное значение JPanel огромно, оно занимает все доступное пространство. Решение состоит в том, чтобы изменить максимальное значение панели. Однако это плохая практика. Я не рекомендую использовать менеджер BoxLayout -- он очень слаб и приводит к плохому коду.

Я рекомендую использовать менеджер MigLayout или менеджер GroupLayout.

Я предлагаю три решения: исправленное решение BoxLayout, решение MigLayout и решение GroupLayout.

Решение BoxLayout

Мы определяем максимальный размер кнопки и меняем размер панели, чтобы он был немного больше размера кнопки.

package com.zetcode;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;


public class BoxLayoutPanel extends JFrame {

    public BoxLayoutPanel() {

        initUI();
    }

    private void initUI() {

        JPanel cpane = (JPanel) getContentPane();
        cpane.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
        cpane.setLayout(new BoxLayout(cpane, 
                BoxLayout.Y_AXIS));        

        JPanel pnl = new JPanel();

        JButton btn1 = new JButton("Button 1");
        JButton btn2 = new JButton("Button 2");

        Dimension dm = btn1.getMaximumSize();
        dm.height += 15;
        dm.width += 15;

        pnl.setMaximumSize(dm);

        pnl.setBackground(Color.black);
        add(pnl);
        add(Box.createVerticalStrut(10));
        pnl.add(btn1);
        btn2.setAlignmentX(Component.CENTER_ALIGNMENT);
        add(btn2);

        setTitle("BoxLayout solution");
        pack();
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                BoxLayoutPanel ex = new BoxLayoutPanel();
                ex.setVisible(true);
            }
        });   
    }
}

Это не чистое решение. Как правило, нам следует избегать вызова getMaximumSize() и setMaximumSize() в коде приложения — это работа менеджера компоновки. Также в трех случаях мы используем фиксированную ширину в пикселях: когда мы определяем пустую границу, вертикальную стойку и максимальный размер панели. Однако этот код не является переносимым. Ширина пикселей меняется при изменении разрешения экрана. Это недостаток менеджера BoxLayout.

Решение MigLayout

Это решение намного чище и более портативно. MigLayout — сторонний менеджер, поэтому нам нужно скачать дополнительные библиотеки.

package com.zetcode;

import java.awt.Color;
import java.awt.EventQueue;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;


public class MigLayoutPanel extends JFrame {

    public MigLayoutPanel(){

        initUI();

        setTitle("MigLayout solution");
        setLocationRelativeTo(null);       
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    private void initUI() {

        JPanel main = new JPanel(new MigLayout("center"));

        JPanel pnl2 = new JPanel();

        JButton btn1 = new JButton("Button 1");
        JButton btn2 = new JButton("Button 2");

        pnl2.setBackground(Color.black);

        pnl2.add(btn1);
        main.add(pnl2, "wrap");
        main.add(btn2, "alignx center");

        add(main);

        pack();
    }


    public static void main(String[] args){

        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                MigLayoutPanel ex = new MigLayoutPanel();
                ex.setVisible(true);
            }
        });
    }
}

Решение MigLayout

Решение GroupLayout

GroupLayout — это встроенный менеджер компоновки. С MigLayout они являются наиболее портативными и гибкими менеджерами компоновки.

package com.zetcode;

import java.awt.Color;
import java.awt.Container;
import java.awt.EventQueue;
import javax.swing.GroupLayout;
import static javax.swing.GroupLayout.Alignment.CENTER;
import static javax.swing.GroupLayout.DEFAULT_SIZE;
import static javax.swing.GroupLayout.PREFERRED_SIZE;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import static javax.swing.LayoutStyle.ComponentPlacement.RELATED;


public class GroupLayoutPanel extends JFrame {

    public GroupLayoutPanel(){

        initUI();

        setTitle("GroupLayout solution");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);        
    }

    private void initUI() {

        Container pane = getContentPane();
        GroupLayout gl = new GroupLayout(pane);
        pane.setLayout(gl); 

        JPanel pnl = new JPanel();

        JButton btn1 = new JButton("Button 1");
        pnl.add(btn1);

        JButton btn2 = new JButton("Button 2");

        pnl.setBackground(Color.black);

        gl.setAutoCreateGaps(true);

        gl.setHorizontalGroup(gl.createSequentialGroup()
                .addContainerGap(DEFAULT_SIZE, Integer.MAX_VALUE)
                .addGroup(gl.createParallelGroup(CENTER)
                        .addComponent(pnl, DEFAULT_SIZE, DEFAULT_SIZE, 
                                PREFERRED_SIZE)
                        .addComponent(btn2))
                .addContainerGap(DEFAULT_SIZE, Integer.MAX_VALUE)
        );

        gl.setVerticalGroup(gl.createSequentialGroup()
                .addContainerGap()
                .addComponent(pnl, DEFAULT_SIZE, DEFAULT_SIZE, 
                        PREFERRED_SIZE)
                .addPreferredGap(RELATED)
                .addComponent(btn2)
                .addContainerGap()
        );

        pack();
    }


    public static void main(String[] args){

        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                GroupLayoutPanel ex = new GroupLayoutPanel();
                ex.setVisible(true);
            }
        });
    }
}

Решение GroupLayout

person Jan Bodnar    schedule 05.08.2014