简体   繁体   中英

Layout not doing what expected in Swing with Java

I am a student and have a project which is supposed to have a specific layout which I have achieved except for some kind of spacing problem due to a bug or due to something I don't know I'm doing wrong and I've fixated so I'm having trouble thinking about approaching it differently. It should look like this:

所需布局

My application looks like this:

当前布局

I am following along with Murach's Java Programming and trying to solve this problem using anything within the scope of the book only.

I have added components to appropriate panels and added those to the main panel with a GridBagLayout to organize everything. The text fields and combo box, for some reason, hang to the right after the radio buttons and check boxes are added to the panel. I have tried creating different panels to reorganize, changed layout settings, tried other layouts, rewrote the whole program, and more. I asked my instructor for help a few days ago but they haven't gotten back to me yet. I read over the chapters for Swing multiple times and ran out of terms to search for on Google.

Edited to add all of the code:

StudentSurvey.java

package student.timothycdykes.studentsurvey;

public class StudentSurvey {

    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(() -> {
            new StudentSurveyFrame();
        });
    }

}

StudentSurveyFrame.java

package student.timothycdykes.studentsurvey;

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

public class StudentSurveyFrame extends JFrame {

    public StudentSurveyFrame(){

        try {
            UIManager.setLookAndFeel(
                UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException | InstantiationException |
                 IllegalAccessException | UnsupportedLookAndFeelException e) {
            System.err.println(e);
        }

        initComponents();
    }

    private void initComponents(){
        setTitle("Student Survey");
        setResizable(false);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationByPlatform(true);
//        setLayout(new FlowLayout(FlowLayout.LEFT));

        // Text Fields
        Dimension dim = new Dimension(150,20);
        JTextField firstNameTextField = new JTextField();
        JTextField lastNameTextField = new JTextField();
        firstNameTextField.setPreferredSize(dim);
        firstNameTextField.setMinimumSize(dim);
        lastNameTextField.setPreferredSize(dim);
        lastNameTextField.setMinimumSize(dim);

        // Combo Box
        String[] countriesList = {"Select a country...", 
            "Albania", 
            "Bulgaria", 
            "Congo", 
            "Guernsey", 
            "Jamaica", 
            "Korea", 
            "Mozambique", 
            "Oman", 
            "Philippines", 
            "United States", 
            "Other"};
        JComboBox countriesComboBox = new JComboBox(countriesList);

        // Radio Buttons
        ButtonGroup eyeColorButtonGroup = new ButtonGroup();
        JRadioButton brownRadioButton = new JRadioButton("Brown");
        JRadioButton greenRadioButton = new JRadioButton("Green");
        JRadioButton blueRadioButton = new JRadioButton("Blue");
        JRadioButton otherRadioButton = new JRadioButton("Other");
        eyeColorButtonGroup.add(brownRadioButton);
        eyeColorButtonGroup.add(greenRadioButton);
        eyeColorButtonGroup.add(blueRadioButton);
        eyeColorButtonGroup.add(otherRadioButton);
        JPanel radioButtonPanel = new JPanel();
        //radioButtonPanel.setBorder(BorderFactory.createEmptyBorder());
        radioButtonPanel.add(brownRadioButton);
        radioButtonPanel.add(greenRadioButton);
        radioButtonPanel.add(blueRadioButton);
        radioButtonPanel.add(otherRadioButton);

        // Check Boxes
        JCheckBox HTMLCheckBox = new JCheckBox("HTML");
        JCheckBox SQLCheckBox = new JCheckBox("SQL");
        JCheckBox javaCheckBox = new JCheckBox("Java");
        JCheckBox androidCheckBox = new JCheckBox("Android");
        JCheckBox pythonCheckBox = new JCheckBox("Python");
        JPanel checkBoxPanel = new JPanel();
        //checkBoxPanel.setBorder(BorderFactory.createEmptyBorder());
        checkBoxPanel.add(HTMLCheckBox);
        checkBoxPanel.add(SQLCheckBox);
        checkBoxPanel.add(javaCheckBox);
        checkBoxPanel.add(androidCheckBox);
        checkBoxPanel.add(pythonCheckBox);

        // Buttons
        JButton submitButton = new JButton("Submit");
        submitButton.addActionListener(e -> {

            // Create a message to append data to
            String message = "Thanks for taking our survey!\n\n"
                    + "Here's the data you entered:\n";


            // Get the name
            String firstName = firstNameTextField.getText();
            String lastName = lastNameTextField.getText();

            // Get the country
            int countryIndex = countriesComboBox.getSelectedIndex();
            String country = countriesList[countryIndex];

            // Get the eye color
            String eyeColor = "";
            if (brownRadioButton.isSelected()) {
                eyeColor = "Brown";
            } else if (greenRadioButton.isSelected()) {
                eyeColor = "Green";
            } else if (blueRadioButton.isSelected()) {
                eyeColor = "Blue";
            } else if (otherRadioButton.isSelected()) {
                eyeColor = "Other";
            }

            // Get the skills
            String skills = "";
            if (HTMLCheckBox.isSelected()) {
                skills += "HTML";
            }
            if (SQLCheckBox.isSelected()) {
                skills += ", SQL";
            }
            if (javaCheckBox.isSelected()) {
                skills += ", Java";
            }
            if (androidCheckBox.isSelected()) {
                skills += ", Android";
            }
            if (pythonCheckBox.isSelected()) {
                skills += ", Python";
            }

            // Validate, append to message, and show a dialog box
            if (Validator.isEmpty(firstName, "First name") && Validator.isEmpty(lastName, "Last name")
                    && Validator.isZeroIndex(countryIndex, "Country") && Validator.isEmpty(eyeColor, "Eye color")) {
                message += "Name: " + firstName + " " + lastName + "\n";
                message += "Country: " + country + "\n";
                message += "Eye color: " + eyeColor + "\n";
                message += "Skills: " + skills;
                JOptionPane.showMessageDialog(this, message, "Message", JOptionPane.INFORMATION_MESSAGE);
            }

        });
        JButton exitButton = new JButton("Exit");
        exitButton.addActionListener(e -> {
           System.exit(0); 
        });
        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
        buttonPanel.add(submitButton);
        buttonPanel.add(exitButton);

        // Grid Panel
        JPanel northGridPanel = new JPanel();
        northGridPanel.setLayout(new GridBagLayout());
        northGridPanel.add(new JLabel("First Name:"), getConstraints(0,0));
        northGridPanel.add(firstNameTextField, getConstraints(1,0));
        northGridPanel.add(new JLabel("Last Name:"), getConstraints(0,1));
        northGridPanel.add(lastNameTextField, getConstraints(1,1));
        northGridPanel.add(new JLabel("Country:"), getConstraints(0,2));
        northGridPanel.add(countriesComboBox, getConstraints(1,2));
        northGridPanel.add(new JLabel("Eye color:"), getConstraints(0,3));
        northGridPanel.add(radioButtonPanel, getConstraints(0,4));
        northGridPanel.add(new JLabel("Programming skills:"), getConstraints(0,5));
        northGridPanel.add(checkBoxPanel, getConstraints(0,6));

        // Construct the frame
        add(northGridPanel, BorderLayout.CENTER);
        add(buttonPanel, BorderLayout.SOUTH);
        pack();
        setVisible(true);
        setLocationRelativeTo(null);
    }

    private GridBagConstraints getConstraints(int x, int y) {
        GridBagConstraints c = new GridBagConstraints();
        c.anchor = GridBagConstraints.LINE_START;
        c.insets = new Insets(5, 5, 0, 5);
        c.gridx = x;
        c.gridy = y;
        return c;
    }
}

Validator.java

package student.timothycdykes.studentsurvey;

import javax.swing.JOptionPane;

public class Validator {

    private static void generateErrorDialog(String field) {
        String message = "";
        message += field + " is a required field."
                + "\nPlease complete this field before submitting.";
        JOptionPane.showMessageDialog(null, message, "Error", JOptionPane.ERROR_MESSAGE);
    }

    public static boolean isEmpty(String string, String field) {
        boolean isValid = true;
        if (string.equals("")) {
            isValid = false;
            generateErrorDialog(field);
        }
        return isValid;
    }

    public static boolean isZeroIndex(int index, String field) {
        boolean isValid = true;
        if(index == 0) {
            isValid = false;
            generateErrorDialog(field);
        }
        return isValid;
    }

}

I would like to add that I know the code is not following best practices. Some of the material in this book is outdated and some of it is just how the instructor requires things to be.

It seems the panels containing the check boxes and radio buttons should span 2 columns of the grid bag layout.

My suspicion was correct. Herein is an MRE implementing the suggestion. I also changed the width of one of the text fields in order to demonstrate the effect of different column sizes.

在此处输入图片说明

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

/* Do NOT extend components, containers or windows without good cause. It is
 done here in order to stick to the spirit of the code in the question. */
public class LayoutProblemGBL extends JFrame {

    LayoutProblemGBL() {
        initComponents();
    }

    private void initComponents() {
        setTitle("Student Survey");
        setResizable(false);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationByPlatform(true);

        // Text Fields
        //Dimension dim = new Dimension(150, 20);
        JTextField firstNameTextField = new JTextField(20);
        JTextField lastNameTextField = new JTextField(18);

        // Combo Box
        String[] countriesList = {"Select a country...",
            "Albania",
            "United States"};
        JComboBox countriesComboBox = new JComboBox(countriesList);

        // Radio Buttons
        JRadioButton brownRadioButton = new JRadioButton("Brown");
        JRadioButton greenRadioButton = new JRadioButton("Green");
        JRadioButton blueRadioButton = new JRadioButton("Blue");
        JRadioButton otherRadioButton = new JRadioButton("Other");
        JPanel radioButtonPanel = new JPanel();
        radioButtonPanel.add(brownRadioButton);
        radioButtonPanel.add(greenRadioButton);
        radioButtonPanel.add(blueRadioButton);
        radioButtonPanel.add(otherRadioButton);

        // Check Boxes
        JCheckBox HTMLCheckBox = new JCheckBox("HTML");
        JCheckBox SQLCheckBox = new JCheckBox("SQL");
        JCheckBox javaCheckBox = new JCheckBox("Java");
        JCheckBox androidCheckBox = new JCheckBox("Android");
        JCheckBox pythonCheckBox = new JCheckBox("Python");
        JPanel checkBoxPanel = new JPanel();
        checkBoxPanel.add(HTMLCheckBox);
        checkBoxPanel.add(SQLCheckBox);
        checkBoxPanel.add(javaCheckBox);
        checkBoxPanel.add(androidCheckBox);
        checkBoxPanel.add(pythonCheckBox);

        // Buttons
        JButton submitButton = new JButton("Submit");
        JButton exitButton = new JButton("Exit");
        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
        buttonPanel.add(submitButton);
        buttonPanel.add(exitButton);

        // Grid Panel
        JPanel northGridPanel = new JPanel();
        northGridPanel.setLayout(new GridBagLayout());
        northGridPanel.add(new JLabel("First Name:"), getConstraints(0, 0));
        northGridPanel.add(firstNameTextField, getConstraints(1, 0));
        northGridPanel.add(new JLabel("Last Name:"), getConstraints(0, 1));
        northGridPanel.add(lastNameTextField, getConstraints(1, 1));
        northGridPanel.add(new JLabel("Country:"), getConstraints(0, 2));
        northGridPanel.add(countriesComboBox, getConstraints(1, 2));
        northGridPanel.add(new JLabel("Eye color:"), getConstraints(0, 3));
        northGridPanel.add(radioButtonPanel, getConstraints(0, 4, 2));
        northGridPanel.add(new JLabel("Programming skills:"), getConstraints(0, 5));
        northGridPanel.add(checkBoxPanel, getConstraints(0, 6, 2));

        // Construct the frame
        add(northGridPanel, BorderLayout.CENTER);
        add(buttonPanel, BorderLayout.SOUTH);
        pack();
        setVisible(true);
        setLocationRelativeTo(null);
    }

    private GridBagConstraints getConstraints(int x, int y) {
        return getConstraints(x, y, 1);
    }

    private GridBagConstraints getConstraints(int x, int y, int width) {
        GridBagConstraints c = new GridBagConstraints();
        c.anchor = GridBagConstraints.LINE_START;
        c.insets = new Insets(5, 5, 0, 5);
        c.gridx = x;
        c.gridy = y;
        c.gridwidth = width;
        return c;
    }

    public static void main(String[] args) {
        Runnable r = () -> {
            new LayoutProblemGBL();
        };
        SwingUtilities.invokeLater(r);
    }
}

The text fields and combo box, for some reason, hang to the right after the radio buttons and check boxes are added to the panel.

You need to understand the concept of spanning cells.

Each cell in the grid will be the size of the largest component added to the column.

So your radio buttons and check box panels are the largest components in the first column, so the other components are displayed in the second column to the right of those components.

So, when you create your constraints for those two panels you need to specify that each panel takes up the space of two columns.

Read the section from the Swing tutorial on How to Use GridBagLayout , specifically you need to look at the gridwidth constraint`.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM