Java JPanel组件放置

Java JPanel组件放置,java,swing,user-interface,jframe,jpanel,Java,Swing,User Interface,Jframe,Jpanel,我试图得到一个基本的图形用户界面程序。它不需要做很多事情,但底部的按钮必须工作。我无法将文本、组合框等组件放置在正确的位置。使用GridBag,我可以用c.gridx和c.gridy更改位置,但方式非常奇怪。如果我把网格值0-7,x为0,所有的东西都在上面。我试图通过更改gridx值将组合框放在文本旁边,结果一切都搞砸了。在我试图移动的组件之后,组件上的对齐已关闭。我该如何解决这个问题?我试过边界布局,但没有成功。实际的变化根本不起作用,然后移动到底部。我该如何解决这个问题?谢谢 /* * T

我试图得到一个基本的图形用户界面程序。它不需要做很多事情,但底部的按钮必须工作。我无法将文本、组合框等组件放置在正确的位置。使用GridBag,我可以用c.gridx和c.gridy更改位置,但方式非常奇怪。如果我把网格值0-7,x为0,所有的东西都在上面。我试图通过更改gridx值将组合框放在文本旁边,结果一切都搞砸了。在我试图移动的组件之后,组件上的对齐已关闭。我该如何解决这个问题?我试过边界布局,但没有成功。实际的变化根本不起作用,然后移动到底部。我该如何解决这个问题?谢谢

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package javaredesign;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Timer;

/**
 *
 * @author 
 */
public class Window extends JFrame {

    //Default global variables
    private JButton submit;
    private JButton cancel;
    private JButton reset;
    private JPanel panel = new JPanel(new GridBagLayout());
    private String searchOutput = "";


    //Default constructor
    public Window() {

        //Title of the window
        super("LIBSYS: Search");

        //Creating the flow layout to which we can work on and adding panel to frame
        setLayout(new FlowLayout());
        add(panel, BorderLayout.SOUTH);

        //Creating the grid to location of the parts
        GridBagConstraints c = new GridBagConstraints();

        //Initializing the buttons
        submit = new JButton("Submit");
        c.insets = new Insets(10, 10, 10, 5);
        c.gridx = 1;
        c.gridy = 20;
        panel.add(submit, c);
        reset = new JButton("Reset");
        c.gridx = 2;
        c.gridy = 20;
        panel.add(reset, c);
        cancel = new JButton("Cancel");
        c.gridx = 3;
        c.gridy = 20;
        panel.add(cancel, c);

        //Handler constructor to do the actionlistening
        Handler handler = new Handler();
        submit.addActionListener(handler);
        reset.addActionListener(handler);
        cancel.addActionListener(handler);

        //Creating the two dropdowns with the words next to them
        JLabel chooseCollection = new JLabel("Choose Collection");
        String[] ccString = {"All", "Mostly", "Some", "Few"};
        JComboBox ccComboBox = new JComboBox(ccString);
        JLabel searchUsing = new JLabel("Search Using");
        String[] suString = {"Title", "Artist", "Arthor", "Type"};
        JComboBox suComboBox = new JComboBox(suString);

        //Adding all the text and dropdown menus to the panel
        c.gridx = 0;
        c.gridy = 24;
        panel.add(chooseCollection, c);
        c.gridx = 0;
        c.gridy = 25;
        panel.add(ccComboBox, c);
        c.gridx = 1;
        c.gridy = 25;
        panel.add(searchUsing, c);
        c.gridx = 0;
        c.gridy = 27;
        panel.add(suComboBox, c);
        c.gridx = 1;
        c.gridy = 27;

        //Setting up the text inputbox
        JLabel keyword = new JLabel("Keyword or phrase");
        JTextField textField = new JTextField(20);

        //Adding lable and text box to the panel
        panel.add(keyword);
        panel.add(textField);
    }

}

问题是您需要了解GridBagLayout。您需要将组件布局到适当的网格上:

因此,您应该有5行12列,以您在图片中描述的方式进行布局。不要介意填充,我试着添加它以使其更具说明性。前三行的每个元素都应该是gridwidth=6,第一行应该是gridx=0,第二行应该是gridx=6。然后,在gridx=6和gridx=9处,yes和no按钮应分别具有gridwidth=3。最后,最后一行按钮应分别具有gridwidth=2和gridx=1、gridx=5和gridx=9。我不使用填充,而是对所有组件使用gbc.anchor=GridBagConstraints.CENTER,以便组件在其网格内居中

我建议对文本字段和组合框使用gbc.fill=GridBagConstraints.HORIZONTAL,这样它们就可以很好地排列起来,但不要忘记将单选按钮和常规按钮设置回gbc.fill=GridBagConstraints.NONE,除非您希望它们也拉伸

我非常随意地更改了您的代码,似乎不符合逻辑顺序:

// Creating the grid to location of the parts
GridBagConstraints c = new GridBagConstraints();

c.anchor = GridBagConstraints.CENTER;

// Initializing the buttons
submit = new JButton("Submit");
c.insets = new Insets(10, 10, 10, 5);
c.gridx = 1;
c.gridy = 5;
c.gridwidth = 2;
panel.add(submit, c);
reset = new JButton("Reset");
c.gridx = 5;
// c.gridy = 20;
panel.add(reset, c);
cancel = new JButton("Cancel");
c.gridx = 9;
// c.gridy = 20;
panel.add(cancel, c);

// Handler constructor to do the actionlistening
Handler handler = new Handler();
submit.addActionListener(handler);
reset.addActionListener(handler);
cancel.addActionListener(handler);

// Creating the two dropdowns with the words next to them
JLabel chooseCollection = new JLabel("Choose Collection");
String[] ccString = { "All", "Mostly", "Some", "Few" };
JComboBox ccComboBox = new JComboBox(ccString);
JLabel searchUsing = new JLabel("Search Using");
String[] suString = { "Title", "Artist", "Arthor", "Type" };
JComboBox suComboBox = new JComboBox(suString);
// Adding all the text and dropdown menus to the panel
c.gridx = 0;
c.gridy = 0;
c.gridwidth = 6;
c.anchor = GridBagConstraints.WEST;
panel.add(chooseCollection, c);
c.gridx = 6;
// c.gridy = 25;

c.fill = GridBagConstraints.HORIZONTAL;
panel.add(ccComboBox, c);
c.gridx = 0;
c.gridy = 2;
c.fill = GridBagConstraints.NONE;
panel.add(searchUsing, c);
c.gridx = 6;
// c.gridy = 27;
c.fill = GridBagConstraints.HORIZONTAL;
panel.add(suComboBox, c);

// Setting up the text inputbox
JLabel keyword = new JLabel("Keyword or phrase");
JTextField textField = new JTextField(20);
// Adding lable and text box to the panel
c.gridx = 0;
c.gridy = 1;
c.fill = GridBagConstraints.NONE;
panel.add(keyword, c);
c.gridx = 6;

panel.add(textField, c);
产生了以下布局:


我会做一个外部边界布局。中间是标签/控件对的GroupLayout。在页面的末尾是按钮的流程布局。

这使用标题边框而不是JLabel来显示LIBSYS搜索。如果它真的需要一个标签,把它放在页面开始的边框布局

import java.awt.*;
import java.util.HashMap;
import java.util.Map;
import javax.swing.*;
import javax.swing.border.*;

public class LibSysSearch {

    private JComponent ui = null;

    LibSysSearch() {
        initUI();
    }

    public void initUI() {
        if (ui != null) {
            return;
        }
        ui = new JPanel(new BorderLayout(4, 4));
        ui.setBorder(new EmptyBorder(4, 4, 4, 4));

        // Here is our control.  This puts a titled border around it, 
        // instead of using a label in the PAGE_START
        JPanel libSysSearchControl = new JPanel(new BorderLayout());
        ui.add(libSysSearchControl);

        JPanel actionPanel = new JPanel(
                new FlowLayout(FlowLayout.CENTER, 15, 15));
        libSysSearchControl.add(actionPanel, BorderLayout.PAGE_END);

        String[] actionNames = {"Search", "Reset", "Cancel"};
        for (String name : actionNames) {
            actionPanel.add(new JButton(name));
        }

        // Use GroupLayout for the label/cotrnl combos.
        // make the arrays for the factory method
        String[] labels = {
            "Choose Collection", "Search Using", 
            "Keyword or phrase", "Adjacent words"
        };
        String[] ccString = {"All", "Mostly", "Some", "Few"};
        String[] suString = {"Title", "Artist", "Arthor", "Type"};

        JPanel confirmAdjacent = new JPanel(new FlowLayout(FlowLayout.LEADING,5,0));
        confirmAdjacent.add(new JRadioButton("Yes", true));
        confirmAdjacent.add(new JRadioButton("No"));

        JComponent[] controls = {
            new JComboBox(ccString),
            new JTextField(20),
            new JComboBox(suString),
            confirmAdjacent
        };

        libSysSearchControl.add(getTwoColumnLayout(labels, controls));

        // throw in a few borders for white space
        Border border = new CompoundBorder(
                new EmptyBorder(10, 10, 10, 10),
                new TitledBorder("LIBSYS Search"));
        border = new CompoundBorder(
                border,
                new EmptyBorder(10, 10, 10, 10));
        libSysSearchControl.setBorder(border);
    }

    public JComponent getUI() {
        return ui;
    }

    public static void main(String[] args) {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception useDefault) {
                }
                LibSysSearch o = new LibSysSearch();

                JFrame f = new JFrame("Library System Search");
                f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                f.setLocationByPlatform(true);

                f.setContentPane(o.getUI());
                f.pack();
                f.setMinimumSize(f.getSize());

                f.setVisible(true);
            }
        };
        SwingUtilities.invokeLater(r);
    }

    /**
     * Provides a JPanel with two columns (labels & fields) laid out using
     * GroupLayout. The arrays must be of equal size.
     *
     * Typical fields would be single line textual/input components such as
     * JTextField, JPasswordField, JFormattedTextField, JSpinner, JComboBox,
     * JCheckBox.. & the multi-line components wrapped in a JScrollPane -
     * JTextArea or (at a stretch) JList or JTable.
     *
     * @param labels The first column contains labels.
     * @param fields The last column contains fields.
     * @param addMnemonics Add mnemonic by next available letter in label text.
     * @return JComponent A JPanel with two columns of the components provided.
     */
    public static JComponent getTwoColumnLayout(
            JLabel[] labels,
            JComponent[] fields,
            boolean addMnemonics) {
        if (labels.length != fields.length) {
            String s = labels.length + " labels supplied for "
                    + fields.length + " fields!";
            throw new IllegalArgumentException(s);
        }
        JComponent panel = new JPanel();
        GroupLayout layout = new GroupLayout(panel);
        panel.setLayout(layout);
        // Turn on automatically adding gaps between components
        layout.setAutoCreateGaps(true);
        // Create a sequential group for the horizontal axis.
        GroupLayout.SequentialGroup hGroup = layout.createSequentialGroup();
        GroupLayout.Group yLabelGroup = layout.createParallelGroup(GroupLayout.Alignment.TRAILING);
        hGroup.addGroup(yLabelGroup);
        GroupLayout.Group yFieldGroup = layout.createParallelGroup();
        hGroup.addGroup(yFieldGroup);
        layout.setHorizontalGroup(hGroup);
        // Create a sequential group for the vertical axis.
        GroupLayout.SequentialGroup vGroup = layout.createSequentialGroup();
        layout.setVerticalGroup(vGroup);

        int p = GroupLayout.PREFERRED_SIZE;
        // add the components to the groups
        for (JLabel label : labels) {
            yLabelGroup.addComponent(label);
        }
        for (Component field : fields) {
            yFieldGroup.addComponent(field, p, p, p);
        }
        for (int ii = 0; ii < labels.length; ii++) {
            vGroup.addGroup(layout.createParallelGroup().
                    addComponent(labels[ii]).
                    addComponent(fields[ii], p, p, p));
        }

        if (addMnemonics) {
            addMnemonics(labels, fields);
        }

        return panel;
    }

    private final static void addMnemonics(
            JLabel[] labels,
            JComponent[] fields) {
        Map<Character, Object> m = new HashMap<Character, Object>();
        for (int ii = 0; ii < labels.length; ii++) {
            labels[ii].setLabelFor(fields[ii]);
            String lwr = labels[ii].getText().toLowerCase();
            for (int jj = 0; jj < lwr.length(); jj++) {
                char ch = lwr.charAt(jj);
                if (m.get(ch) == null && Character.isLetterOrDigit(ch)) {
                    m.put(ch, ch);
                    labels[ii].setDisplayedMnemonic(ch);
                    break;
                }
            }
        }
    }

    /**
     * Provides a JPanel with two columns (labels & fields) laid out using
     * GroupLayout. The arrays must be of equal size.
     *
     * @param labelStrings Strings that will be used for labels.
     * @param fields The corresponding fields.
     * @return JComponent A JPanel with two columns of the components provided.
     */
    public static JComponent getTwoColumnLayout(
            String[] labelStrings,
            JComponent[] fields) {
        JLabel[] labels = new JLabel[labelStrings.length];
        for (int ii = 0; ii < labels.length; ii++) {
            labels[ii] = new JLabel(labelStrings[ii]);
        }
        return getTwoColumnLayout(labels, fields);
    }

    /**
     * Provides a JPanel with two columns (labels & fields) laid out using
     * GroupLayout. The arrays must be of equal size.
     *
     * @param labels The first column contains labels.
     * @param fields The last column contains fields.
     * @return JComponent A JPanel with two columns of the components provided.
     */
    public static JComponent getTwoColumnLayout(
            JLabel[] labels,
            JComponent[] fields) {
        return getTwoColumnLayout(labels, fields, true);
    }
}

我可能会这样做:

public class Test {

    public Test() {

        JFrame frame = new JFrame();
        JPanel mainPanel = new JPanel(new GridLayout(0, 1));
        JPanel chooseCollectionPanel = new JPanel(new BorderLayout());
        JPanel keywordPanel = new JPanel(new BorderLayout());
        JPanel searchCategoryPanel = new JPanel(new BorderLayout());
        // ...
        mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        chooseCollectionPanel.setBorder(BorderFactory.createEmptyBorder(5, 0,
                5, 0));
        keywordPanel.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));
        searchCategoryPanel.setBorder(BorderFactory.createEmptyBorder(5, 0, 5,
                0));

        JLabel chooseCollectionLabel = new JLabel("Choose Collection: ");
        JComboBox<String> chooseCollectionCB = new JComboBox<String>();
        chooseCollectionCB.addItem("All");
        chooseCollectionPanel.add(chooseCollectionLabel, BorderLayout.WEST);
        chooseCollectionPanel.add(chooseCollectionCB, BorderLayout.CENTER);

        JLabel chooseCollectionkeywordLabel = new JLabel("Choose Collection: ");
        JTextField keywordCB = new JTextField(10);
        keywordPanel.add(chooseCollectionkeywordLabel, BorderLayout.WEST);
        keywordPanel.add(keywordCB, BorderLayout.CENTER);
        // ...

        mainPanel.add(chooseCollectionPanel);
        mainPanel.add(keywordPanel);
        mainPanel.add(searchCategoryPanel);
        // ...
        frame.add(mainPanel);
        frame.setSize(400, 400);
        frame.pack();
        frame.setVisible(true);
    }

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

我不会强迫按钮与其他组件的布局相同。它们是独立的,并且应该自由浮动,间隔均匀

按钮面板应位于具有flowlayout的面板集中。然后,此面板应添加到边框布局位于南部的框架中

其余的组件应放入带有gridbaglayout的面板中,并添加到中心的框架中

gridbaglayout面板应将其所有组件设置在图片中列出的坐标处。如果组件包含两个以上的单元格ie combo,则将gridWidth属性设置为2


提供所需GUI布局的ASCII艺术图或简单绘图,并提供一个没有诸如公共类处理程序实现ActionListener之类的东西的图形{..我知道没有功能的按钮在真实的应用程序中是无用的,但是没有必要演示布局问题。不要尝试在单个组件中执行此操作,使用多个JPanel来维护UI的各个元素,并关注它们的布局要求,构建每个层,如果需要,使用不同的布局管理器o在你得到你需要的结果之前,你不可能有像c.gridy=25这样的东西。我不明白你想用这样的东西做什么。你有27行吗?这似乎很不可能。你的目标是得到你的图片的样子吗?另外,在最后,你只需添加关键字和文本字段,而没有GridBagConstaints对象。我只是使用25作为测试值,看看是否有任何变化。我只是不断增加值,看看它是否会离开屏幕,但是的。当然,GridBagLayouts的强大演示是可行的,但我更喜欢在它的关系容器字段和按钮中分别分解UI,例如,通过这种方式可以添加将更多组件放入容器中,而不会对其他组件的布局产生不利影响……只是说;@MadProgrammer是的,我不是GUI向导,事实上,我希望避免像瘟疫一样的GUI布局。对我来说,我发现GridBagLayout足够通用,我可以用它做任何事情,而不必了解其他组件布局,这就是我一直在做的事情。说实话,据我所知,swing已经死了,甚至JavaFX也没有得到广泛的应用。在我看来,CSS已经赢得了胜利,布局应该通过web技术来完成,Java应该留在后端。一幅图描绘了千言万语,所以一个人的世界THA+1。解释得很好。