使用 JButton 在运行时添加新面板

Use a JButton to add new panels at runtime

我觉得作为初学者,我可能在应用程序构建方面吃得太多了。也就是说,我正在为一位朋友开发一个应用程序,该应用程序将提示每个 JPanel 将提供字段以创建稍后使用的对象。我想要发生的是,当面板加载时,它会显示一个对象创建面板和一个按钮,如果用户想要创建多个面板,则可以动态添加一个新面板(加号按钮将添加新面板)。

我画了一些东西来说明这一点:

根据我非常有限的理解,我可以创建一个面板来容纳这些子面板,然后向“+”按钮添加一个动作侦听器以创建新面板。我能想到的实现它的唯一方法是为我想添加的面板创建一个构造函数。这可能吗?让我告诉你我有什么:

package com.company;

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

/**
 * Created by Travis on 3/1/2015.
 */
public class MainSnakeGui extends JFrame{

    protected int panelCount;


    //row 1
    JPanel row1 = new JPanel();
    JLabel splitSnakeLabel = new JLabel("Create a Split Snake", JLabel.CENTER);

    //row 2
    JPanel row2 = new JPanel();
    JButton addButton = new JButton("+");



    public MainSnakeGui() {
        super("Snake Channels");

        setSize(550, 400);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        GridLayout layout = new GridLayout(5, 1, 10, 10);
        setLayout(layout);

        FlowLayout layout1 = new FlowLayout(FlowLayout.CENTER, 10, 10);
        row1.setLayout(layout1);
        row1.add(splitSnakeLabel);
        add(row1);

        GridLayout layout2 = new GridLayout(1, 2, 10, 10);
        row2.setLayout(layout2);
        row2.add(addButton);
        MainSnakeConstructor snakePanel = new MainSnakeConstructor();
        row2.add(snakePanel);
        add(row2);

        setVisible(true);
    }

    public static void setLookAndFeel () {
        try {
            UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
        } catch (Exception e) {
        }
    }

    public static void main(String[] arg) {
        MainSnakeGui.setLookAndFeel();
        MainSnakeGui frame = new MainSnakeGui();
    }
}

这是构造函数:

package com.company;

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

/**
 * Created by Travis on 3/1/2015.
 */
public class MainSnakeConstructor extends JFrame {

    public  MainSnakeConstructor () {
        JPanel splitSnakeRow = new JPanel();
        JLabel snakeNameLabel = new JLabel("Snake Name");
        JLabel channelCountLabel = new JLabel("Channel Count");
        JCheckBox artistSuppliedCheckBox = new JCheckBox("Artist Supplied?");
        JTextField snakeNameTextField = new JTextField(30);
        JTextField channelCountTextField =  new JTextField(3);

        GridLayout layout = new GridLayout(3,2,10,10);
        splitSnakeRow.setLayout(layout);
        splitSnakeRow.add(snakeNameLabel);
        splitSnakeRow.add(channelCountLabel);
        splitSnakeRow.add(artistSuppliedCheckBox);
        splitSnakeRow.add(snakeNameTextField);
        splitSnakeRow.add(channelCountTextField);
        add(splitSnakeRow);
    }
}

换个角度思考。您想要一个允许您添加新面板的按钮,因此您实际上只需要一个按钮。

从那里开始,您需要某种通用面板来为用户提供您想要的功能(创建面板)。然后,当用户单击添加按钮时,您创建一个新的创建面板并将其添加到用于显示它们的容器中,例如...

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;

public class Test {

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

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

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            JButton btnAdd = new JButton("+");
            setLayout(new BorderLayout());
            JPanel buttons = new JPanel(new FlowLayout(FlowLayout.LEFT));
            buttons.add(btnAdd);
            add(buttons, BorderLayout.NORTH);

            JPanel content = new JPanel(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            gbc.weighty = 1;
            content.add(new JPanel(), gbc);

            add(new JScrollPane(content));

            btnAdd.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    CreationPane pane = new CreationPane();
                    int insertAt = Math.max(0, content.getComponentCount() - 1);
                    GridBagConstraints gbc = new GridBagConstraints();
                    gbc.gridwidth = GridBagConstraints.REMAINDER;
                    gbc.fill = GridBagConstraints.HORIZONTAL;
                    gbc.weightx = 1;
                    content.add(pane, gbc, insertAt);
                    content.revalidate();
                    content.repaint();
                }
            });

        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

    }

    public static class CreationPane extends JPanel {

        private static int count;

        public CreationPane() {

            setLayout(new GridBagLayout());
            add(new JLabel("Make it so " + (count++)));
            setBorder(new CompoundBorder(new LineBorder(Color.BLACK), new EmptyBorder(10, 10, 10, 10)));

        }

    }

}

完成所有这些后,我更喜欢 SwingLabs 的 VerticalLayout 管理器,SwingX 库,它基本上做同样的事情...