Java:使用JTextField数组计算平均值每次都返回0

时间:2018-04-08 23:13:24

标签: java swing awt

我试图编写一个Java GUI程序来计算用户定义的课程数量的平均值,但是,每当我尝试做的时候,数组似乎都是空的:System.out.println(gTextFields[0]);,我可以不知道问题是什么,我希望有人可以帮忙。

这是我的代码:

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

public class Swinggg extends JFrame {

double course1 = 90;
double course2 = 80;


private JLabel numOfCoursesLabel;
private JTextField numOfFallCourses;
private JButton clickButton;
private JButton calcAvg;
private JLabel label;
private JTextField textField;
private JLabel gLabel;
private JTextField gTextField;

public Swinggg() {
    super("Title");
    setLayout(null);
    // Setting up the label
    numOfCoursesLabel = new JLabel("Please enter the number of courses that you completed in Fall 17/18: ");
    numOfCoursesLabel.setFont(new Font("Tahoma", Font.BOLD, 15));
    Dimension labelSize = numOfCoursesLabel.getPreferredSize();
    numOfCoursesLabel.setBounds(25, 20, labelSize.width, labelSize.height);
    add(numOfCoursesLabel);
    // Setting up the text field
    numOfFallCourses = new JTextField(20);
    Dimension textFieldSize = numOfFallCourses.getPreferredSize();
    numOfFallCourses.setBounds(130, 60, textFieldSize.width, textFieldSize.height + 10);
    numOfFallCourses.setFont(new Font("Tahoma", Font.BOLD, 18));
    add(numOfFallCourses);
    // Setting up the click button
    clickButton = new JButton("Click");
    Dimension buttonSize = clickButton.getPreferredSize();
    clickButton.setBounds(360, 55, buttonSize.width + 20, buttonSize.height + 10);
    clickButton.setFont(new Font("Tahoma", Font.BOLD, 16));
    add(clickButton);
    // Setting up the calculate average button
    calcAvg = new JButton("Calculate Average");
    Dimension calcAvgSize = calcAvg.getPreferredSize();
    calcAvg.setBounds(180, 100, 200, 40);
    calcAvg.setFont(new Font("Tahoma", Font.BOLD, 16));
    add(calcAvg);

    TheHandler handler = new TheHandler();
    clickButton.addActionListener(handler);
    calcAvg.addActionListener(handler);
    numOfFallCourses.addActionListener(handler);
}


private class TheHandler implements ActionListener {

    public void actionPerformed(ActionEvent event) {
        int theNumOfCourses = 0;
        int yDynamicPositioning = 120;
        JTextField[] textFields = new JTextField[theNumOfCourses];
        JTextField[] gTextFields = new JTextField[theNumOfCourses];
        if (event.getSource() == clickButton) {
            theNumOfCourses = Integer.parseInt(numOfFallCourses.getText());
            JLabel[] labels = new JLabel[theNumOfCourses];
            textFields = new JTextField[theNumOfCourses];
            JLabel[] gLabels = new JLabel[theNumOfCourses];
            gTextFields = new JTextField[theNumOfCourses];
            for (int i = 0; i < labels.length; i++) {
                yDynamicPositioning = yDynamicPositioning + 35;
                // Course name labels creation
                label = new JLabel("Course Name " + i);
                Dimension labelSize = label.getPreferredSize();
                label.setFont(new Font("Tahoma", Font.BOLD, 15));
                label.setBounds(25, yDynamicPositioning, labelSize.width + 40, labelSize.height);
                add(label);

                // Course name text fields creation
                textField = new JTextField(10);
                textField.setFont(new Font("Tahoma", Font.BOLD, 15));
                Dimension textFieldSize = textField.getPreferredSize();
                textField.setBounds(160, yDynamicPositioning, textFieldSize.width, textFieldSize.height + 2);
                textFields[i] = textField;
                add(textField);

                // Course grades labels creation
                gLabel = new JLabel("Course Grade " + i);
                Dimension gLabelSize = gLabel.getPreferredSize();
                gLabel.setFont(new Font("Tahoma", Font.BOLD, 15));
                gLabel.setBounds(300, yDynamicPositioning, gLabelSize.width + 40, gLabelSize.height);
                add(gLabel);

                // Course grades text fields creation
                gTextField = new JTextField(10);
                gTextField.setFont(new Font("Tahoma", Font.BOLD, 15));
                Dimension gTextFieldSize = gTextField.getPreferredSize();
                gTextField.setBounds(440, yDynamicPositioning, gTextFieldSize.width, gTextFieldSize.height + 2);
                gTextFields[i] = gTextField;
                add(gTextField);


            }
            calcAvg.setBounds(210, yDynamicPositioning + 50, 200, 40);
            System.out.println(gTextFields[0].getText());
            clickButton.setVisible(false);
            setSize(650, 250 + (labels.length * 40) + 40);
            validate();
            revalidate();
            repaint();
        } else if (event.getSource() == calcAvg) {
            int counter = 0;
            double sum = 0;
            try {
                while (counter < gTextFields.length) {
                    sum = sum + Double.parseDouble(gTextFields[counter].getText());
                    System.out.println(gTextFields[0]);
                    counter++;
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                System.out.println("Exception occurred!");
            }
            double avg = ((course1 + course2) + sum) / (2 + gTextFields.length);
            System.out.println(sum);

        }
    }

}

public static void main(String[] args) {

    Swinggg objct = new Swinggg();
    objct.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    objct.setSize(600, 250);
    objct.setVisible(true);

}

}

1 个答案:

答案 0 :(得分:2)

每次调用侦听器时,它都会创建一个完全 new 的JTextField数组(实际上是两个新数组),所以你试图从空的JTextFields中提取数据。

总之,这是你的听众正在做的事情:

public void actionPerformed(ActionEvent event) {

    // create two arrays of JTextField, textFields and gTextFields
    // this happens **every time the listener is called!**

    if (event.getSource() == clickButton) {

        // fill the array with objects and put them into the GUI

    } else if (event.getSource() == calcAvg) {

        // extract data from the JTextField arrays, but **not** the displayed array of fields
        // rather of a new array that has never been added to the GUI

    }
}

而是将数组声明为类的字段,创建JTextField并将它们放在构造函数中,而不是放在侦听器中。使用侦听器从中提取数据。如果你想在创建程序时不要显示JTextField网格,仍然你应该创建网格,将它放入代码构造函数的JPanel中,然后在ActionListener中使用CardLayout交换网格进入视图。

修改

你说:

  

我认为在按下clickButton后,数组大小取决于用户输入,我认为不能这样做

然后将空数组声明为字段,并在侦听器中填充一次。 但是不要在侦听器中多次创建数组。你需要注意这样做。您可以检查null以防止这种情况发生。

如,

//  fields declared in *class* and are null:
private JTextField[] textFields;
private JTextField[] gTextFields;

    private class TheHandler implements ActionListener 

        public void actionPerformed(ActionEvent event) {
            if (event.getSource() == clickButton) {
                // get user input

                if (textFields == null && gTextFields == null) {
                    textFields = new JTextField[someInt];
                    gTextFields = new JTextField[someInt];
                    // use for loop to fill arrays and place into GUI

                }

            } else if (event.getSource() == calcAvg) {

                // extract data from the JTextField arrays,
            }
        }
    }

更好的是:使用List<JTextField> textFields = new ArrayList<>();。这样您就不需要事先知道数组的大小了。

附注:setLayout(null);

虽然null布局和setBounds()似乎是Swing新手,比如创建复杂GUI的最简单和最好的方法,但是你创建的Swing GUI越多,使用它们时会遇到更严重的困难。当GUI调整大小时,它们不会调整组件的大小,它们是增强或维护的皇室女巫,当它们被放置在滚动窗格中时它们完全失败,当它们在所有平台上观看时或者与原始平台不同的屏幕分辨率时它们看起来很糟糕

修改

注意,如果这是我的程序,我会尝试使用JTable进一步简化它以保存我的课程名称/课程成绩数据,并为我做平均计算。例如:

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;

@SuppressWarnings("serial")
public class Swinggg2 extends JPanel {
    // default table model holds no data, but displays the column header names, course/grade
    private MyTableModel tableModel = new MyTableModel(0);
    private JTable myTable = new JTable(tableModel);

    // get the number of courses in a JSpinner, from 1 to 100
    private JSpinner spinner = new JSpinner(new SpinnerNumberModel(1, 1, 100, 1));
    private JTextField averageField = new JTextField(10);

    public Swinggg2() {
        // create our GUI
        // first the top JPanel to get the number of courses
        JPanel courseNumberPanel = new JPanel();
        courseNumberPanel.add(new JLabel("Please enter the number of courses that you completed in Fall 17/18:"));
        courseNumberPanel.add(spinner);
        courseNumberPanel.add(new JButton(new AbstractAction("Show Courses") {

            @Override
            public void actionPerformed(ActionEvent e) {
                int rowCount = (int) spinner.getValue();
                tableModel = new MyTableModel(rowCount);
                myTable.setModel(tableModel);
            }
        }));

        // then the JScrollPane to hold the JTable
        JScrollPane scrollPane = new JScrollPane(myTable);
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

        // then create the bottom JPanel to calculate and display the average grade
        averageField.setEditable(false);
        JPanel calcAveragePanel = new JPanel();
        calcAveragePanel.add(new JLabel("Calculated Average Grade:"));
        calcAveragePanel.add(averageField);
        calcAveragePanel.add(new JButton(new AbstractAction("Calculate Average") {

            @Override
            public void actionPerformed(ActionEvent e) {
                // if user is still editing a cell, STOP editing
                if (myTable.isEditing()) {
                    myTable.getCellEditor().stopCellEditing();
                }

                // extract the average value from the table model and display it
                double average = tableModel.getAverageGrade();
                String averageText = String.format("%.3f", average);
                averageField.setText(averageText);
            }
        }));

        // give the JPanel a layout and add components to it, top, center, bottom
        int gap = 3;
        setBorder(BorderFactory.createEmptyBorder(gap, gap, gap, gap));
        setLayout(new BorderLayout());
        add(courseNumberPanel, BorderLayout.PAGE_START);
        add(scrollPane, BorderLayout.CENTER);
        add(calcAveragePanel, BorderLayout.PAGE_END);
    }

    // create and show the GUI
    private static void createAndShowGui() {
        Swinggg2 mainPanel = new Swinggg2();

        JFrame frame = new JFrame("Course Grade Average");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        // do everything on the Swing event thread
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}

// each row of our JTable holds a Course object's data
class Course {
    private String name;
    private double grade;

    public Course(String name, double grade) {
        this.name = name;
        this.grade = grade;
    }

    public String getName() {
        return name;
    }

    public double getGrade() {
        return grade;
    }

    // hashcode and equals based on name (or courseNumber)
}

// table model to hold and display our course data
@SuppressWarnings("serial")
class MyTableModel extends DefaultTableModel {
    // Table's column header Strings
    public static final String[] COL_NAMES = {"Course Name", "Course Grade"};

    public MyTableModel(int rowCount) {
        super(COL_NAMES, rowCount);
    }

    @Override
    public int getColumnCount() {
        return COL_NAMES.length;
    }

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        if (columnIndex == 1) {
            return Double.class;
        }
        return super.getColumnClass(columnIndex);
    }

    public void addRow(Course course) {
        Object[] rowData = {course.getName(), course.getGrade()};
        super.addRow(rowData);
    }

    public Course getRow(int rowIndex) {
        //get data, handling nulls carefully
        String name = (String) getValueAt(rowIndex, 0);
        name = name == null? "" : name;
        Object colObject = getValueAt(rowIndex, 1);
        double grade = colObject == null ? 0.0 : (double) colObject;
        return new Course(name, grade);
    }


    public double getAverageGrade() {
        // if no rows, either return 0.0 
        if (getRowCount() == 0) {
            return 0.0;  // ? or throw an exception ?
        }

        // summation variable
        double total = 0.0;
        for (int i = 0; i < getRowCount(); i++) {
            // iterate through the table extracting grades and adding to total
            total += getRow(i).getGrade();
        }

        // calculate and return the average
        return total / getRowCount();
    }
}