使用标签文本更新 JPanel
Updating JPanel with Label Texts
我正在开发一个应用程序,它将通过 MyPanel class 中的按钮和文本框从用户那里获取信息。我想显示用户在 DisplayTable 面板中输入的课程信息。我希望它在每次按下 MyPanel class 中的添加课程按钮时更新。我尝试从 MyPanel class 调用 setLabelText 方法,实际功能应该做的是更新面板并在单击按钮时显示传递列表中每个元素的文本,但仍然无法更新.您能告诉我如何在每次按下 addCourseButton 时更新 DisplayPanel 的信息标签文本吗?
Class 主要
public class Main {
//TODO
// PREVENT TYPE MISMATCH IN TEXT FIELDS
// DISPLAY A TABLE OF COURSE NAMES - COURSE CREDITS - COURSE NAME AND THE GPA
// CLEAN UP
public static void main(String[] args) {
new MyFrame();
}
}
Class MyFrame
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class MyFrame extends JFrame{
MainPanel mainPanel;
MyFrame(){
mainPanel = new MainPanel();
this.add(mainPanel);
this.setTitle("GPA Calculator");
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(500,500);
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
}
Class 主面板
import javax.swing.*;
public class MainPanel extends JPanel {
DisplayPanel displayPanel = new DisplayPanel();
MyPanel myPanel = new MyPanel(displayPanel);
MainPanel() {
this.add(myPanel);
this.add(displayPanel);
}
}
Class 我的面板
import javax.swing.*;
import javax.swing.Timer;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
import java.util.List;
public class MyPanel extends JPanel implements ActionListener{
ArrayList<String> courseNames;
ArrayList<Integer> courseCredits;
ArrayList<Double> courseGrades;
Thread thread;
JLabel nameLabel;
JLabel creditLabel;
JLabel gradeLabel;
JTextField nameField;
JTextField creditField;
JTextField gradeField;
JButton calculateButton;
JButton addCourseButton;
JButton resetButton;
JLabel message;
DisplayPanel displayPanel;
double result = 0;
int tempInt = 0;
double tempDouble = 0;
MyPanel(DisplayPanel displayPanel) {
this.displayPanel = new DisplayPanel();
message = new JLabel();
message.setHorizontalAlignment(JLabel.CENTER);
message.setFont(new Font("Helvetica Neue", Font.PLAIN, 35));
message.setForeground(new Color(0xA1683A));
message.setAlignmentX(JLabel.CENTER_ALIGNMENT);
courseNames = new ArrayList();
courseCredits = new ArrayList();
courseGrades = new ArrayList();
nameLabel = new JLabel();
nameLabel.setHorizontalAlignment(JLabel.CENTER);
nameLabel.setText("Course Name");
nameLabel.setFont(new Font("Helvetica Neue", Font.PLAIN, 25));
nameLabel.setForeground(new Color(0xA1683A));
nameLabel.setAlignmentX(JLabel.CENTER_ALIGNMENT);
nameField = new JTextField();
nameField.setPreferredSize(new Dimension(300,30));
nameField.setMaximumSize(nameField.getPreferredSize());
creditLabel = new JLabel();
creditLabel.setHorizontalAlignment(JLabel.CENTER);
creditLabel.setText("Course Credits(ECTS)");
creditLabel.setFont(new Font("Helvetica Neue", Font.PLAIN, 25));
creditLabel.setForeground(new Color(0xA1683A));
creditLabel.setAlignmentX(JLabel.CENTER_ALIGNMENT);
creditField = new JTextField();
creditField.setPreferredSize(new Dimension(300,30));
creditField.setMaximumSize(creditField.getPreferredSize());
gradeLabel = new JLabel();
gradeLabel.setHorizontalAlignment(JLabel.CENTER);
gradeLabel.setText("Your Grade");
gradeLabel.setFont(new Font("Helvetica Neue", Font.PLAIN, 25));
gradeLabel.setForeground(new Color(0xA1683A));
gradeLabel.setAlignmentX(JLabel.CENTER_ALIGNMENT);
gradeField = new JTextField();
gradeField.setPreferredSize(new Dimension(300,30));
gradeField.setMaximumSize(gradeField.getPreferredSize());
resetButton = new JButton("Reset");
resetButton.setAlignmentX(JLabel.CENTER_ALIGNMENT);
resetButton.addActionListener(this);
addCourseButton = new JButton("Add Course");
addCourseButton.setAlignmentX(JLabel.CENTER_ALIGNMENT);
addCourseButton.addActionListener(this);
calculateButton = new JButton("Calculate GPA");
calculateButton.setAlignmentX(JLabel.CENTER_ALIGNMENT);
calculateButton.addActionListener(this);
//spacing and adding the elements
this.add(Box.createRigidArea(new Dimension(0,20)));
this.add(nameLabel);
this.add(Box.createRigidArea(new Dimension(0,10)));
this.add(nameField);
this.add(Box.createRigidArea(new Dimension(0,20)));
this.add(creditLabel);
this.add(Box.createRigidArea(new Dimension(0,10)));
this.add(creditField);
this.add(Box.createRigidArea(new Dimension(0,20)));
this.add(gradeLabel);
this.add(Box.createRigidArea(new Dimension(0,10)));
this.add(gradeField);
this.add(Box.createRigidArea(new Dimension(0,20)));
this.add(addCourseButton);
this.add(Box.createRigidArea(new Dimension(0,5)));
this.add(calculateButton);
this.add(Box.createRigidArea(new Dimension(0,5)));
this.add(resetButton);
this.add(Box.createRigidArea(new Dimension(0,30)));
this.add(message);
this.setPreferredSize(new Dimension(500, 500));
this.setBackground(new Color(0xEED2CC));
this.setLayout(new BoxLayout(this,BoxLayout.Y_AXIS));
}
//calculate the GPA
public double calculateGPA(){
for (Integer courseCredit : courseCredits) {
tempInt += courseCredit;
}
for(int i = 0; i<courseGrades.size();i++){
tempDouble += courseGrades.get(i) * courseCredits.get(i);
}
return tempDouble/tempInt;
}
@Override
public void actionPerformed(ActionEvent e) throws NumberFormatException {
if(e.getSource().equals(addCourseButton)){
//add items from the textFields to lists
String tempText = nameField.getText();
int tempCredit = Integer.parseInt(creditField.getText());
double tempGrade = Double.parseDouble(gradeField.getText());
courseNames.add(tempText);
courseCredits.add(tempCredit);
courseGrades.add(tempGrade);
//set textFields to empty
nameField.setText("");
creditField.setText("");
gradeField.setText("");
//display a message for 3 seconds
thread = new Thread();
thread.start();
message.setText("Course Added Successfully!");
Timer timer = new Timer(3000, a -> message.setText(null));
timer.setRepeats(false);
timer.start();
//add to table panel
displayPanel.setLabelText(courseNames,courseCredits,courseGrades);
//displayPanel.update();
}
//calculate the GPA, initialize the display panel
//to display the courses names-credits-results and the gpa
//as a table
if(e.getSource().equals(calculateButton)){
result = calculateGPA();
message.setText(result + "");
}
//clear the lists,text fields and the message
//get rid of the table panel
if(e.getSource().equals(resetButton)){
courseNames.clear();
courseGrades.clear();
courseCredits.clear();
tempDouble = 0;
tempInt = 0;
displayPanel.removeAll();
displayPanel.repaint();
nameField.setText("");
creditField.setText("");
gradeField.setText("");
message.setText(null);
}
}
}
Class 显示面板
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
public class DisplayPanel extends JPanel {
JLabel infoLabel;
public DisplayPanel() {
this.setPreferredSize(new Dimension(500, 500));
this.setBackground(new Color(0xEED2CC));
this.setLayout(null);
infoLabel = new JLabel();
infoLabel.setHorizontalAlignment(JLabel.LEFT);
infoLabel.setFont(new Font("Helvetica Neue", Font.PLAIN, 35));
infoLabel.setForeground(new Color(0xA1683A));
infoLabel.setAlignmentX(JLabel.CENTER_ALIGNMENT);
infoLabel.setBackground(Color.RED);
infoLabel.setOpaque(true);
this.add(infoLabel);
}
public void setLabelText(ArrayList<String> courseNames, ArrayList<Integer> courseCredits, ArrayList<Double> courseGrades) {
this.removeAll();
this.add(infoLabel);
this.repaint();
this.revalidate();
for (String name : courseNames) {
infoLabel.setText(name + "\t" + courseCredits.get(courseNames.indexOf(name)) + "\t" + courseGrades.get(courseNames.indexOf(name)));
}
infoLabel.setOpaque(true);
}
}
您正在创建两个 DisplayPanel,将一个添加到 GUI 并尝试更改另一个 non-displayed DisplayPanel 的状态。
class MainPanel extends JPanel {
DisplayPanel displayPanel = new DisplayPanel(); // *** HERE ***
MyPanel myPanel = new MyPanel(displayPanel);
MainPanel() {
this.add(myPanel);
this.add(displayPanel);
}
}
public class MyPanel extends JPanel implements ActionListener {
// ....
DisplayPanel displayPanel;
// ...
MyPanel(DisplayPanel displayPanel) {
this.displayPanel = new DisplayPanel(); // *** and HERE ***
// ...
}
// ...
}
事实上,在 MainPanel 中,您试图将 DisplayPanel object 添加到两个不同的容器中,这在 Swing 中是不合法的,只有第二种添加方法才算数。
建议:
首先也是最重要的:创建一个class来保存你的关键信息显示。在我下面的例子中,我展示了如何做到这一点,如何创建一个 CourseInfo class 来保存你最终将显示的每一“行”数据。事实上,无论你决定如何显示数据,我认为首先做这件事是你可以而且应该做的最重要的事情。
创建一个且仅此一个组件,在需要时添加它并更改其状态。
使用 JList 或更好的 JTable 来显示数据。
避免空布局和 setBounds,而是使用布局管理器。在此处查看布局管理器教程:在此处查看布局管理器教程:Layout Manager Tutorial
避免并行数组或 ArrayLists。而是创建一个 class 来保存一行数据,并创建一个您 fill-up.
的这种类型的 ArrayList
首先关注让你的 GUI 正常工作,其次让它变得漂亮等等。换句话说,在担心字体、颜色等问题之前,请确保一切正常并能正常显示。
所以,这是一个使用 JTable 和自定义 table 模型的示例,显示如下:
首先,一个 class 用于保存存储在 JTable 的每一行中的关键信息,称为 CourseInfo,它具有名称 String、credits int 和 grades double 字段:
public class CourseInfo {
private String name;
private int credits;
private double grades;
public CourseInfo(String name, int credits, double grades) {
this.name = name;
this.credits = credits;
this.grades = grades;
}
public String getName() {
return name;
}
public int getCredits() {
return credits;
}
public double getGrades() {
return grades;
}
}
接下来是一个 TableModel class,它包含 collection 上述信息并允许在 JTable 中显示它。我扩展了 DefaultTableModel,因为它 pre-wired 带有内部侦听器,在发生更改时通知外部 objects(JTable 本身和添加到它的任何侦听器)。
构造函数调用接受 COLUMNS String 数组的超级构造函数,该数组保存 JTable header 中显示的列的名称。内部(超级)模型包含 collection 的 CourseInfo object,棘手的部分是在 3 列中显示一个 CourseInfo object。这是通过使列计数为 3 并覆盖 getValueAt(...)
使其 returns 根据列参数
成为正确的 CourseInfo 字段来完成的
import javax.swing.table.DefaultTableModel;
@SuppressWarnings("serial")
public class CourseTableModel extends DefaultTableModel {
private static final String[] COLUMNS = { "Name", "Credits", "Grades" };
public CourseTableModel() {
super(COLUMNS, 0);
}
public void addCourseInfo(CourseInfo courseInfo) {
super.addRow(new CourseInfo[] { courseInfo });
}
@Override
public int getColumnCount() {
return COLUMNS.length;
}
@Override
public Object getValueAt(int row, int column) {
CourseInfo courseInfo = (CourseInfo) super.getValueAt(row, 0);
switch (column) {
case 0:
return courseInfo.getName();
case 1:
return courseInfo.getCredits();
case 2:
return courseInfo.getGrades();
default:
throw new IllegalArgumentException("Unexpected value: " + column);
}
}
@Override
public Class<?> getColumnClass(int columnIndex) {
if (getRowCount() > 0) {
return getValueAt(0, columnIndex).getClass();
} else {
return super.getColumnClass(columnIndex);
}
}
}
接下来是显示JTable的JPanel,TablePanel。它还在字段中显示 GPA。请注意,这个 class 没有太多内容,大部分程序逻辑都从中提取出来,因此它专注于视图或 GUI 方面。 TableModel 通过其构造函数传递给它。它允许外部 classes 通过 setGpa(...)
方法设置 gpaField 中显示的内容:
import java.awt.BorderLayout;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
@SuppressWarnings("serial")
public class TablePanel extends JPanel {
private JTable table;
private JScrollPane scrollPane;
private JTextField gpaField = new JTextField(10);
public TablePanel(CourseTableModel tableModel) {
int gap = 20;
setBorder(BorderFactory.createEmptyBorder(gap, gap, gap, gap));
setBackground(CoursesMainPanel.BACKGROUND);
table = new JTable(tableModel);
scrollPane = new JScrollPane(table);
table.setOpaque(false);
scrollPane.setOpaque(false);
scrollPane.getViewport().setOpaque(false);
JPanel gpaPanel = new JPanel();
gpaPanel.setOpaque(false);
gpaPanel.add(new JLabel("GPA:"));
gpaPanel.add(Box.createHorizontalStrut(10));
gpaPanel.add(gpaField);
gpaField.setEditable(false);
setLayout(new BorderLayout());
add(scrollPane);
add(gpaPanel, BorderLayout.PAGE_END);
}
public void setGpa(String gpaText) {
gpaField.setText(gpaText);
}
}
接下来是 GetInfoPanel,这是一个获取用户输入的 JPanel。它有 3 个 JTextField、JLabel、JButton,并通过 GridBagLayout 进行组织。它有一个 calcGpaButton,它是该程序早期版本的遗留物,但在我将 GPA 计算放入 TableModelListener 后被禁用(并且可能应该被删除)。
它也没有太多的程序逻辑,并将其外包给控件 class,CoursesControl,它包含按钮的 ActionListeners 调用的代码。它有 public 方法,例如 public String getCourseName() {...
允许控件 class 在需要时从这个 object 中提取信息。
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.KeyEvent;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
@SuppressWarnings("serial")
public class GetInfoPanel extends JPanel {
private static final Font LABEL_FONT = new Font("Helvetica Neue", Font.PLAIN, 35);
private static final int TXT_FLD_COLS = 15;
private JTextField courseNameField = new JTextField(TXT_FLD_COLS);
private JTextField courseCreditsField = new JTextField(TXT_FLD_COLS);
private JTextField courseGradesField = new JTextField(TXT_FLD_COLS);
private JButton addCourseButton = new JButton("Add Course");
private JButton calcGpaButton = new JButton("Calculate GPA"); // TODO: delete
private JButton resetButton = new JButton("Reset");
private JButton exitButton = new JButton("Exit");
private int row = 0;
private int insetGap = 2;
private CoursesControl control;
public GetInfoPanel() {
int gap = 20;
setBorder(BorderFactory.createEmptyBorder(gap, gap, gap, gap));
setLayout(new GridBagLayout());
setBackground(CoursesMainPanel.BACKGROUND);
addToPanel("Course Name", courseNameField);
addToPanel("Course Credits", courseCreditsField);
addToPanel("Your Grade", courseGradesField);
addCourseButton.addActionListener(e -> addCourse());
calcGpaButton.addActionListener(e -> calcGpa());
resetButton.addActionListener(e -> reset());
exitButton.addActionListener(e -> exit());
addCourseButton.setMnemonic(KeyEvent.VK_A);
calcGpaButton.setMnemonic(KeyEvent.VK_C);
resetButton.setMnemonic(KeyEvent.VK_R);
exitButton.setMnemonic(KeyEvent.VK_X);
calcGpaButton.setEnabled(false); // Not needed
JPanel buttonPanel = new JPanel(new GridLayout(1, 0, 5, 0));
buttonPanel.setOpaque(false);
buttonPanel.add(addCourseButton);
buttonPanel.add(calcGpaButton);
buttonPanel.add(resetButton);
buttonPanel.add(exitButton);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = row;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(6 * insetGap, 3 * insetGap, 3 * insetGap, 3 * insetGap);
add(buttonPanel, gbc);
}
public String getCourseName() {
return courseNameField.getText();
}
public String getCourseCredits() {
return courseCreditsField.getText();
}
public String getCourseGrades() {
return courseGradesField.getText();
}
public void clear() {
courseNameField.setText("");
courseCreditsField.setText("");
courseGradesField.setText("");
courseNameField.requestFocusInWindow();
}
public void setControl(CoursesControl control) {
this.control = control;
}
private void addCourse() {
if (control != null) {
control.addCourse();
}
clear();
}
// TODO: delete as it is not really needed
private void calcGpa() {
if (control != null) {
control.calcGpa();
}
}
private void reset() {
if (control != null) {
control.reset();
}
clear();
}
private void exit() {
if (control != null) {
control.exit();
}
}
private void addToPanel(String title, JTextField textField) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.CENTER;
gbc.gridx = 0;
gbc.gridy = row;
row++;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(3 * insetGap, 3 * insetGap, 0, 3 * insetGap);
JLabel label = new JLabel(title);
label.setFont(LABEL_FONT);
label.setForeground(CoursesMainPanel.LABEL_FOREGROUND);
label.setHorizontalAlignment(SwingConstants.CENTER);
add(label, gbc);
gbc.gridy = row;
row++;
gbc.insets.bottom = 3 * insetGap;
textField.setFont(textField.getFont().deriveFont(20f));
add(textField, gbc);
}
}
接下来是 CoursesControl class,它包含程序的大部分逻辑。这包含对视图的 GUI classes 和视图侦听器调用的方法的引用。 addCourse()
方法从 GetInfoPanel 中提取文本,然后验证数字文本确实是数字,如果不是则显示错误。如果数据良好,它会用数据创建一个新的 CourseInfo object,然后通过调用 tableModel.addCourseInfo(courseInfo);
向 table 模型添加一行。它将一个 TableModelListener 添加到 table 模型,每当模型发生变化时,这个 class 通过在 TablePanel 实例上调用 tablePanel.setGpa
来计算和显示 GPA:
import java.awt.Window;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
public class CoursesControl {
private GetInfoPanel getInfoPanel;
private CourseTableModel tableModel;
private TablePanel tablePanel;
public void setGetInfoPanel(GetInfoPanel getInfoPanel) {
this.getInfoPanel = getInfoPanel;
}
public void setTableModel(CourseTableModel tableModel) {
this.tableModel = tableModel;
tableModel.addTableModelListener(new TableListener());
}
public void setTablePanel(TablePanel tablePanel) {
this.tablePanel = tablePanel;
}
public void addCourse() {
if (getInfoPanel == null || tableModel == null) {
return;
}
String courseName = getInfoPanel.getCourseName();
String courseCreditsTxt = getInfoPanel.getCourseCredits();
String courseGradesTxt = getInfoPanel.getCourseGrades();
int courseCredits = 0;
try {
courseCredits = Integer.parseInt(courseCreditsTxt);
} catch (NumberFormatException e) {
String message = "Course credits should be an integer";
String title = "Invalid Input";
int type = JOptionPane.ERROR_MESSAGE;
JOptionPane.showMessageDialog(getInfoPanel, message, title, type);
getInfoPanel.clear();
return;
}
double courseGrades = 0.0;
try {
courseGrades = Double.parseDouble(courseGradesTxt);
} catch (NumberFormatException e) {
String message = "Course grades should be an number";
String title = "Invalid Input";
int type = JOptionPane.ERROR_MESSAGE;
JOptionPane.showMessageDialog(getInfoPanel, message, title, type);
getInfoPanel.clear();
return;
}
CourseInfo courseInfo = new CourseInfo(courseName, courseCredits, courseGrades);
tableModel.addCourseInfo(courseInfo);
}
private class TableListener implements TableModelListener {
@Override
public void tableChanged(TableModelEvent e) {
if (tablePanel == null) {
return;
}
int rows = tableModel.getRowCount();
if (rows == 0) {
tablePanel.setGpa("");
} else {
double sum = 0.0;
int totalCredits = 0;
for (int row = 0; row < rows; row++) {
int credits = (int) tableModel.getValueAt(row, 1);
double grade = (double) tableModel.getValueAt(row, 2);
totalCredits += credits;
sum += credits * grade;
}
double gpa = sum / totalCredits;
tablePanel.setGpa(String.format("%.2f", gpa));
}
}
}
public void reset() {
if (tableModel != null) {
tableModel.setRowCount(0);
}
}
public void exit() {
if (getInfoPanel != null) {
Window window = SwingUtilities.getWindowAncestor(getInfoPanel);
window.dispose();
}
}
// TODO: delete as it isn't needed
public void calcGpa() {
// This is not really needed, since the GPA is calculated in a table model listener
}
}
最后,一个主要的 class 将它们放在一起,创建一个 JFrame,并显示它。这将创建此产品中的主要参与者,并通过将视图 objects 传递给控件并将控件传递给需要它的视图 objects 来将它们连接在一起:
import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
@SuppressWarnings("serial")
public class CoursesMainPanel extends JPanel {
public static final Color BACKGROUND = new Color(0xEED2CC);
public static final Color LABEL_FOREGROUND = new Color(0xA1683A);
private CoursesControl control = new CoursesControl();
private GetInfoPanel getInfoPanel = new GetInfoPanel();
private CourseTableModel tableModel = new CourseTableModel();
private TablePanel tablePanel = new TablePanel(tableModel);
public CoursesMainPanel() {
getInfoPanel.setControl(control);
control.setGetInfoPanel(getInfoPanel);
control.setTableModel(tableModel);
control.setTablePanel(tablePanel);
int gap = 2;
setLayout(new GridLayout(1, 2, gap, gap));
add(getInfoPanel);
add(tablePanel);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new CoursesMainPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
我会集中精力解决您眼前的问题,即在 class DisplayPanel
.
中的 infoLabel
中显示文本
你有三个问题。第一个在 class MyPanel
.
的构造函数中
MyPanel(DisplayPanel displayPanel) {
this.displayPanel = new DisplayPanel();
您正在忽略构造函数参数并创建 DisplayPanel
的新实例。因此,class MyPanel
的成员 displayPanel
与您在 class MainPanel
中创建的对象不同。因此,您在 DisplayPanel
上调用的方法是 而不是 添加到 MainPanel
。您需要将该行更改为以下内容。
MyPanel(DisplayPanel displayPanel) {
this.displayPanel = displayPanel;
第二个问题是您在 DisplayPanel
中设置了空布局。当没有 layout manager 时,您需要显式设置添加到 JPanel
的任何组件的边界。你没有这样做,因此你的 JLabel
没有显示。只需从 DisplayPanel
的构造函数中删除这一行
this.setLayout(null);
最后,在 class DisplayPanel
的方法 setLabelText
中,您只需通过方法 setText
更改 JLabel
文本。无需删除所有组件并再次添加它们。方法应该如下。
public void setLabelText(ArrayList<String> courseNames, ArrayList<Integer> courseCredits, ArrayList<Double> courseGrades) {
StringBuilder sb = new StringBuilder();
for (String name : courseNames) {
sb.append(name + "\t" + courseCredits.get(courseNames.indexOf(name)) + "\t" + courseGrades.get(courseNames.indexOf(name)));
}
infoLabel.setText(sb.toString());
}
编辑
如果我的任务是制作这个应用程序,我会做类似下面的事情。
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.text.ParseException;
import javax.swing.JButton;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableModel;
import javax.swing.text.MaskFormatter;
public class GpaCalcs implements Runnable {
private DefaultTableModel tableModel;
private JFormattedTextField courseCreditsTextField;
private JFormattedTextField gradeTextField;
private JFrame frame;
private JTable table;
private JTextField courseNameTextField;
public void run() {
try {
createAndDisplayGui();
}
catch (Exception x) {
throw new RuntimeException(x);
}
}
private void addCourse(ActionEvent event) {
Object[] row = new Object[3];
row[0] = courseNameTextField.getText();
row[1] = courseCreditsTextField.getValue();
row[2] = gradeTextField.getValue();
tableModel.addRow(row);
}
private void createAndDisplayGui() throws ParseException {
frame = new JFrame("GPA Calculator");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private void createButtonsPanel(JPanel formPanel, GridBagConstraints gbc) {
JPanel buttonsPanel = new JPanel();
JButton addCourseButton = new JButton("Add Course");
addCourseButton.addActionListener(this::addCourse);
buttonsPanel.add(addCourseButton);
JButton calcGpaButton = new JButton("Calculate GPA");
buttonsPanel.add(calcGpaButton);
JButton resetButton = new JButton("Reset");
resetButton.addActionListener(this::reset);
buttonsPanel.add(resetButton);
gbc.gridwidth = 3;
formPanel.add(buttonsPanel, gbc);
}
private JScrollPane createDisplayPanel() {
String[] columns = new String[]{"Course", "Credits", "Grade"};
tableModel = new DefaultTableModel(columns, 0);
table = new JTable(tableModel);
JScrollPane scrollPane = new JScrollPane(table);
return scrollPane;
}
private JPanel createFormPanel() throws ParseException {
JPanel formPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.LINE_START;
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets.bottom = 5;
gbc.insets.left = 5;
gbc.insets.right = 5;
gbc.insets.top = 5;
JLabel courseNameLabel = new JLabel("Course Name");
formPanel.add(courseNameLabel, gbc);
gbc.gridx = 1;
courseNameTextField = new JTextField(10);
formPanel.add(courseNameTextField, gbc);
gbc.gridx = 0;
gbc.gridy = 1;
JLabel courseCreditLabel = new JLabel("Course Credits (ECTS)");
formPanel.add(courseCreditLabel, gbc);
gbc.gridx = 1;
MaskFormatter formatter = new MaskFormatter("####"); // throws java.text.ParseException
courseCreditsTextField = new JFormattedTextField(formatter);
courseCreditsTextField.setColumns(10);
formPanel.add(courseCreditsTextField, gbc);
gbc.gridx = 0;
gbc.gridy = 2;
JLabel gradeLabel = new JLabel("Your Grade");
formPanel.add(gradeLabel, gbc);
gbc.gridx = 1;
formatter = new MaskFormatter("#.##");
gradeTextField = new JFormattedTextField(formatter);
gradeTextField.setColumns(10);
formPanel.add(gradeTextField, gbc);
gbc.gridx = 0;
gbc.gridy = 3;
createButtonsPanel(formPanel, gbc);
return formPanel;
}
private JPanel createMainPanel() throws ParseException {
JPanel mainPanel = new JPanel(new GridLayout(0, 2));
mainPanel.add(createFormPanel());
mainPanel.add(createDisplayPanel());
return mainPanel;
}
private void reset(ActionEvent event) {
courseNameTextField.setText("");
courseCreditsTextField.setText("");
gradeTextField.setText("");
}
public static void main(String[] args) {
EventQueue.invokeLater(new GpaCalcs());
}
}
我正在开发一个应用程序,它将通过 MyPanel class 中的按钮和文本框从用户那里获取信息。我想显示用户在 DisplayTable 面板中输入的课程信息。我希望它在每次按下 MyPanel class 中的添加课程按钮时更新。我尝试从 MyPanel class 调用 setLabelText 方法,实际功能应该做的是更新面板并在单击按钮时显示传递列表中每个元素的文本,但仍然无法更新.您能告诉我如何在每次按下 addCourseButton 时更新 DisplayPanel 的信息标签文本吗?
Class 主要
public class Main {
//TODO
// PREVENT TYPE MISMATCH IN TEXT FIELDS
// DISPLAY A TABLE OF COURSE NAMES - COURSE CREDITS - COURSE NAME AND THE GPA
// CLEAN UP
public static void main(String[] args) {
new MyFrame();
}
}
Class MyFrame
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class MyFrame extends JFrame{
MainPanel mainPanel;
MyFrame(){
mainPanel = new MainPanel();
this.add(mainPanel);
this.setTitle("GPA Calculator");
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(500,500);
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
}
Class 主面板
import javax.swing.*;
public class MainPanel extends JPanel {
DisplayPanel displayPanel = new DisplayPanel();
MyPanel myPanel = new MyPanel(displayPanel);
MainPanel() {
this.add(myPanel);
this.add(displayPanel);
}
}
Class 我的面板
import javax.swing.*;
import javax.swing.Timer;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
import java.util.List;
public class MyPanel extends JPanel implements ActionListener{
ArrayList<String> courseNames;
ArrayList<Integer> courseCredits;
ArrayList<Double> courseGrades;
Thread thread;
JLabel nameLabel;
JLabel creditLabel;
JLabel gradeLabel;
JTextField nameField;
JTextField creditField;
JTextField gradeField;
JButton calculateButton;
JButton addCourseButton;
JButton resetButton;
JLabel message;
DisplayPanel displayPanel;
double result = 0;
int tempInt = 0;
double tempDouble = 0;
MyPanel(DisplayPanel displayPanel) {
this.displayPanel = new DisplayPanel();
message = new JLabel();
message.setHorizontalAlignment(JLabel.CENTER);
message.setFont(new Font("Helvetica Neue", Font.PLAIN, 35));
message.setForeground(new Color(0xA1683A));
message.setAlignmentX(JLabel.CENTER_ALIGNMENT);
courseNames = new ArrayList();
courseCredits = new ArrayList();
courseGrades = new ArrayList();
nameLabel = new JLabel();
nameLabel.setHorizontalAlignment(JLabel.CENTER);
nameLabel.setText("Course Name");
nameLabel.setFont(new Font("Helvetica Neue", Font.PLAIN, 25));
nameLabel.setForeground(new Color(0xA1683A));
nameLabel.setAlignmentX(JLabel.CENTER_ALIGNMENT);
nameField = new JTextField();
nameField.setPreferredSize(new Dimension(300,30));
nameField.setMaximumSize(nameField.getPreferredSize());
creditLabel = new JLabel();
creditLabel.setHorizontalAlignment(JLabel.CENTER);
creditLabel.setText("Course Credits(ECTS)");
creditLabel.setFont(new Font("Helvetica Neue", Font.PLAIN, 25));
creditLabel.setForeground(new Color(0xA1683A));
creditLabel.setAlignmentX(JLabel.CENTER_ALIGNMENT);
creditField = new JTextField();
creditField.setPreferredSize(new Dimension(300,30));
creditField.setMaximumSize(creditField.getPreferredSize());
gradeLabel = new JLabel();
gradeLabel.setHorizontalAlignment(JLabel.CENTER);
gradeLabel.setText("Your Grade");
gradeLabel.setFont(new Font("Helvetica Neue", Font.PLAIN, 25));
gradeLabel.setForeground(new Color(0xA1683A));
gradeLabel.setAlignmentX(JLabel.CENTER_ALIGNMENT);
gradeField = new JTextField();
gradeField.setPreferredSize(new Dimension(300,30));
gradeField.setMaximumSize(gradeField.getPreferredSize());
resetButton = new JButton("Reset");
resetButton.setAlignmentX(JLabel.CENTER_ALIGNMENT);
resetButton.addActionListener(this);
addCourseButton = new JButton("Add Course");
addCourseButton.setAlignmentX(JLabel.CENTER_ALIGNMENT);
addCourseButton.addActionListener(this);
calculateButton = new JButton("Calculate GPA");
calculateButton.setAlignmentX(JLabel.CENTER_ALIGNMENT);
calculateButton.addActionListener(this);
//spacing and adding the elements
this.add(Box.createRigidArea(new Dimension(0,20)));
this.add(nameLabel);
this.add(Box.createRigidArea(new Dimension(0,10)));
this.add(nameField);
this.add(Box.createRigidArea(new Dimension(0,20)));
this.add(creditLabel);
this.add(Box.createRigidArea(new Dimension(0,10)));
this.add(creditField);
this.add(Box.createRigidArea(new Dimension(0,20)));
this.add(gradeLabel);
this.add(Box.createRigidArea(new Dimension(0,10)));
this.add(gradeField);
this.add(Box.createRigidArea(new Dimension(0,20)));
this.add(addCourseButton);
this.add(Box.createRigidArea(new Dimension(0,5)));
this.add(calculateButton);
this.add(Box.createRigidArea(new Dimension(0,5)));
this.add(resetButton);
this.add(Box.createRigidArea(new Dimension(0,30)));
this.add(message);
this.setPreferredSize(new Dimension(500, 500));
this.setBackground(new Color(0xEED2CC));
this.setLayout(new BoxLayout(this,BoxLayout.Y_AXIS));
}
//calculate the GPA
public double calculateGPA(){
for (Integer courseCredit : courseCredits) {
tempInt += courseCredit;
}
for(int i = 0; i<courseGrades.size();i++){
tempDouble += courseGrades.get(i) * courseCredits.get(i);
}
return tempDouble/tempInt;
}
@Override
public void actionPerformed(ActionEvent e) throws NumberFormatException {
if(e.getSource().equals(addCourseButton)){
//add items from the textFields to lists
String tempText = nameField.getText();
int tempCredit = Integer.parseInt(creditField.getText());
double tempGrade = Double.parseDouble(gradeField.getText());
courseNames.add(tempText);
courseCredits.add(tempCredit);
courseGrades.add(tempGrade);
//set textFields to empty
nameField.setText("");
creditField.setText("");
gradeField.setText("");
//display a message for 3 seconds
thread = new Thread();
thread.start();
message.setText("Course Added Successfully!");
Timer timer = new Timer(3000, a -> message.setText(null));
timer.setRepeats(false);
timer.start();
//add to table panel
displayPanel.setLabelText(courseNames,courseCredits,courseGrades);
//displayPanel.update();
}
//calculate the GPA, initialize the display panel
//to display the courses names-credits-results and the gpa
//as a table
if(e.getSource().equals(calculateButton)){
result = calculateGPA();
message.setText(result + "");
}
//clear the lists,text fields and the message
//get rid of the table panel
if(e.getSource().equals(resetButton)){
courseNames.clear();
courseGrades.clear();
courseCredits.clear();
tempDouble = 0;
tempInt = 0;
displayPanel.removeAll();
displayPanel.repaint();
nameField.setText("");
creditField.setText("");
gradeField.setText("");
message.setText(null);
}
}
}
Class 显示面板
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
public class DisplayPanel extends JPanel {
JLabel infoLabel;
public DisplayPanel() {
this.setPreferredSize(new Dimension(500, 500));
this.setBackground(new Color(0xEED2CC));
this.setLayout(null);
infoLabel = new JLabel();
infoLabel.setHorizontalAlignment(JLabel.LEFT);
infoLabel.setFont(new Font("Helvetica Neue", Font.PLAIN, 35));
infoLabel.setForeground(new Color(0xA1683A));
infoLabel.setAlignmentX(JLabel.CENTER_ALIGNMENT);
infoLabel.setBackground(Color.RED);
infoLabel.setOpaque(true);
this.add(infoLabel);
}
public void setLabelText(ArrayList<String> courseNames, ArrayList<Integer> courseCredits, ArrayList<Double> courseGrades) {
this.removeAll();
this.add(infoLabel);
this.repaint();
this.revalidate();
for (String name : courseNames) {
infoLabel.setText(name + "\t" + courseCredits.get(courseNames.indexOf(name)) + "\t" + courseGrades.get(courseNames.indexOf(name)));
}
infoLabel.setOpaque(true);
}
}
您正在创建两个 DisplayPanel,将一个添加到 GUI 并尝试更改另一个 non-displayed DisplayPanel 的状态。
class MainPanel extends JPanel {
DisplayPanel displayPanel = new DisplayPanel(); // *** HERE ***
MyPanel myPanel = new MyPanel(displayPanel);
MainPanel() {
this.add(myPanel);
this.add(displayPanel);
}
}
public class MyPanel extends JPanel implements ActionListener {
// ....
DisplayPanel displayPanel;
// ...
MyPanel(DisplayPanel displayPanel) {
this.displayPanel = new DisplayPanel(); // *** and HERE ***
// ...
}
// ...
}
事实上,在 MainPanel 中,您试图将 DisplayPanel object 添加到两个不同的容器中,这在 Swing 中是不合法的,只有第二种添加方法才算数。
建议:
首先也是最重要的:创建一个class来保存你的关键信息显示。在我下面的例子中,我展示了如何做到这一点,如何创建一个 CourseInfo class 来保存你最终将显示的每一“行”数据。事实上,无论你决定如何显示数据,我认为首先做这件事是你可以而且应该做的最重要的事情。
创建一个且仅此一个组件,在需要时添加它并更改其状态。
使用 JList 或更好的 JTable 来显示数据。
避免空布局和 setBounds,而是使用布局管理器。在此处查看布局管理器教程:在此处查看布局管理器教程:Layout Manager Tutorial
避免并行数组或 ArrayLists。而是创建一个 class 来保存一行数据,并创建一个您 fill-up.
的这种类型的 ArrayList首先关注让你的 GUI 正常工作,其次让它变得漂亮等等。换句话说,在担心字体、颜色等问题之前,请确保一切正常并能正常显示。
所以,这是一个使用 JTable 和自定义 table 模型的示例,显示如下:
首先,一个 class 用于保存存储在 JTable 的每一行中的关键信息,称为 CourseInfo,它具有名称 String、credits int 和 grades double 字段:
public class CourseInfo {
private String name;
private int credits;
private double grades;
public CourseInfo(String name, int credits, double grades) {
this.name = name;
this.credits = credits;
this.grades = grades;
}
public String getName() {
return name;
}
public int getCredits() {
return credits;
}
public double getGrades() {
return grades;
}
}
接下来是一个 TableModel class,它包含 collection 上述信息并允许在 JTable 中显示它。我扩展了 DefaultTableModel,因为它 pre-wired 带有内部侦听器,在发生更改时通知外部 objects(JTable 本身和添加到它的任何侦听器)。
构造函数调用接受 COLUMNS String 数组的超级构造函数,该数组保存 JTable header 中显示的列的名称。内部(超级)模型包含 collection 的 CourseInfo object,棘手的部分是在 3 列中显示一个 CourseInfo object。这是通过使列计数为 3 并覆盖 getValueAt(...)
使其 returns 根据列参数
import javax.swing.table.DefaultTableModel;
@SuppressWarnings("serial")
public class CourseTableModel extends DefaultTableModel {
private static final String[] COLUMNS = { "Name", "Credits", "Grades" };
public CourseTableModel() {
super(COLUMNS, 0);
}
public void addCourseInfo(CourseInfo courseInfo) {
super.addRow(new CourseInfo[] { courseInfo });
}
@Override
public int getColumnCount() {
return COLUMNS.length;
}
@Override
public Object getValueAt(int row, int column) {
CourseInfo courseInfo = (CourseInfo) super.getValueAt(row, 0);
switch (column) {
case 0:
return courseInfo.getName();
case 1:
return courseInfo.getCredits();
case 2:
return courseInfo.getGrades();
default:
throw new IllegalArgumentException("Unexpected value: " + column);
}
}
@Override
public Class<?> getColumnClass(int columnIndex) {
if (getRowCount() > 0) {
return getValueAt(0, columnIndex).getClass();
} else {
return super.getColumnClass(columnIndex);
}
}
}
接下来是显示JTable的JPanel,TablePanel。它还在字段中显示 GPA。请注意,这个 class 没有太多内容,大部分程序逻辑都从中提取出来,因此它专注于视图或 GUI 方面。 TableModel 通过其构造函数传递给它。它允许外部 classes 通过 setGpa(...)
方法设置 gpaField 中显示的内容:
import java.awt.BorderLayout;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
@SuppressWarnings("serial")
public class TablePanel extends JPanel {
private JTable table;
private JScrollPane scrollPane;
private JTextField gpaField = new JTextField(10);
public TablePanel(CourseTableModel tableModel) {
int gap = 20;
setBorder(BorderFactory.createEmptyBorder(gap, gap, gap, gap));
setBackground(CoursesMainPanel.BACKGROUND);
table = new JTable(tableModel);
scrollPane = new JScrollPane(table);
table.setOpaque(false);
scrollPane.setOpaque(false);
scrollPane.getViewport().setOpaque(false);
JPanel gpaPanel = new JPanel();
gpaPanel.setOpaque(false);
gpaPanel.add(new JLabel("GPA:"));
gpaPanel.add(Box.createHorizontalStrut(10));
gpaPanel.add(gpaField);
gpaField.setEditable(false);
setLayout(new BorderLayout());
add(scrollPane);
add(gpaPanel, BorderLayout.PAGE_END);
}
public void setGpa(String gpaText) {
gpaField.setText(gpaText);
}
}
接下来是 GetInfoPanel,这是一个获取用户输入的 JPanel。它有 3 个 JTextField、JLabel、JButton,并通过 GridBagLayout 进行组织。它有一个 calcGpaButton,它是该程序早期版本的遗留物,但在我将 GPA 计算放入 TableModelListener 后被禁用(并且可能应该被删除)。
它也没有太多的程序逻辑,并将其外包给控件 class,CoursesControl,它包含按钮的 ActionListeners 调用的代码。它有 public 方法,例如 public String getCourseName() {...
允许控件 class 在需要时从这个 object 中提取信息。
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.KeyEvent;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
@SuppressWarnings("serial")
public class GetInfoPanel extends JPanel {
private static final Font LABEL_FONT = new Font("Helvetica Neue", Font.PLAIN, 35);
private static final int TXT_FLD_COLS = 15;
private JTextField courseNameField = new JTextField(TXT_FLD_COLS);
private JTextField courseCreditsField = new JTextField(TXT_FLD_COLS);
private JTextField courseGradesField = new JTextField(TXT_FLD_COLS);
private JButton addCourseButton = new JButton("Add Course");
private JButton calcGpaButton = new JButton("Calculate GPA"); // TODO: delete
private JButton resetButton = new JButton("Reset");
private JButton exitButton = new JButton("Exit");
private int row = 0;
private int insetGap = 2;
private CoursesControl control;
public GetInfoPanel() {
int gap = 20;
setBorder(BorderFactory.createEmptyBorder(gap, gap, gap, gap));
setLayout(new GridBagLayout());
setBackground(CoursesMainPanel.BACKGROUND);
addToPanel("Course Name", courseNameField);
addToPanel("Course Credits", courseCreditsField);
addToPanel("Your Grade", courseGradesField);
addCourseButton.addActionListener(e -> addCourse());
calcGpaButton.addActionListener(e -> calcGpa());
resetButton.addActionListener(e -> reset());
exitButton.addActionListener(e -> exit());
addCourseButton.setMnemonic(KeyEvent.VK_A);
calcGpaButton.setMnemonic(KeyEvent.VK_C);
resetButton.setMnemonic(KeyEvent.VK_R);
exitButton.setMnemonic(KeyEvent.VK_X);
calcGpaButton.setEnabled(false); // Not needed
JPanel buttonPanel = new JPanel(new GridLayout(1, 0, 5, 0));
buttonPanel.setOpaque(false);
buttonPanel.add(addCourseButton);
buttonPanel.add(calcGpaButton);
buttonPanel.add(resetButton);
buttonPanel.add(exitButton);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = row;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(6 * insetGap, 3 * insetGap, 3 * insetGap, 3 * insetGap);
add(buttonPanel, gbc);
}
public String getCourseName() {
return courseNameField.getText();
}
public String getCourseCredits() {
return courseCreditsField.getText();
}
public String getCourseGrades() {
return courseGradesField.getText();
}
public void clear() {
courseNameField.setText("");
courseCreditsField.setText("");
courseGradesField.setText("");
courseNameField.requestFocusInWindow();
}
public void setControl(CoursesControl control) {
this.control = control;
}
private void addCourse() {
if (control != null) {
control.addCourse();
}
clear();
}
// TODO: delete as it is not really needed
private void calcGpa() {
if (control != null) {
control.calcGpa();
}
}
private void reset() {
if (control != null) {
control.reset();
}
clear();
}
private void exit() {
if (control != null) {
control.exit();
}
}
private void addToPanel(String title, JTextField textField) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.CENTER;
gbc.gridx = 0;
gbc.gridy = row;
row++;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(3 * insetGap, 3 * insetGap, 0, 3 * insetGap);
JLabel label = new JLabel(title);
label.setFont(LABEL_FONT);
label.setForeground(CoursesMainPanel.LABEL_FOREGROUND);
label.setHorizontalAlignment(SwingConstants.CENTER);
add(label, gbc);
gbc.gridy = row;
row++;
gbc.insets.bottom = 3 * insetGap;
textField.setFont(textField.getFont().deriveFont(20f));
add(textField, gbc);
}
}
接下来是 CoursesControl class,它包含程序的大部分逻辑。这包含对视图的 GUI classes 和视图侦听器调用的方法的引用。 addCourse()
方法从 GetInfoPanel 中提取文本,然后验证数字文本确实是数字,如果不是则显示错误。如果数据良好,它会用数据创建一个新的 CourseInfo object,然后通过调用 tableModel.addCourseInfo(courseInfo);
向 table 模型添加一行。它将一个 TableModelListener 添加到 table 模型,每当模型发生变化时,这个 class 通过在 TablePanel 实例上调用 tablePanel.setGpa
来计算和显示 GPA:
import java.awt.Window;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
public class CoursesControl {
private GetInfoPanel getInfoPanel;
private CourseTableModel tableModel;
private TablePanel tablePanel;
public void setGetInfoPanel(GetInfoPanel getInfoPanel) {
this.getInfoPanel = getInfoPanel;
}
public void setTableModel(CourseTableModel tableModel) {
this.tableModel = tableModel;
tableModel.addTableModelListener(new TableListener());
}
public void setTablePanel(TablePanel tablePanel) {
this.tablePanel = tablePanel;
}
public void addCourse() {
if (getInfoPanel == null || tableModel == null) {
return;
}
String courseName = getInfoPanel.getCourseName();
String courseCreditsTxt = getInfoPanel.getCourseCredits();
String courseGradesTxt = getInfoPanel.getCourseGrades();
int courseCredits = 0;
try {
courseCredits = Integer.parseInt(courseCreditsTxt);
} catch (NumberFormatException e) {
String message = "Course credits should be an integer";
String title = "Invalid Input";
int type = JOptionPane.ERROR_MESSAGE;
JOptionPane.showMessageDialog(getInfoPanel, message, title, type);
getInfoPanel.clear();
return;
}
double courseGrades = 0.0;
try {
courseGrades = Double.parseDouble(courseGradesTxt);
} catch (NumberFormatException e) {
String message = "Course grades should be an number";
String title = "Invalid Input";
int type = JOptionPane.ERROR_MESSAGE;
JOptionPane.showMessageDialog(getInfoPanel, message, title, type);
getInfoPanel.clear();
return;
}
CourseInfo courseInfo = new CourseInfo(courseName, courseCredits, courseGrades);
tableModel.addCourseInfo(courseInfo);
}
private class TableListener implements TableModelListener {
@Override
public void tableChanged(TableModelEvent e) {
if (tablePanel == null) {
return;
}
int rows = tableModel.getRowCount();
if (rows == 0) {
tablePanel.setGpa("");
} else {
double sum = 0.0;
int totalCredits = 0;
for (int row = 0; row < rows; row++) {
int credits = (int) tableModel.getValueAt(row, 1);
double grade = (double) tableModel.getValueAt(row, 2);
totalCredits += credits;
sum += credits * grade;
}
double gpa = sum / totalCredits;
tablePanel.setGpa(String.format("%.2f", gpa));
}
}
}
public void reset() {
if (tableModel != null) {
tableModel.setRowCount(0);
}
}
public void exit() {
if (getInfoPanel != null) {
Window window = SwingUtilities.getWindowAncestor(getInfoPanel);
window.dispose();
}
}
// TODO: delete as it isn't needed
public void calcGpa() {
// This is not really needed, since the GPA is calculated in a table model listener
}
}
最后,一个主要的 class 将它们放在一起,创建一个 JFrame,并显示它。这将创建此产品中的主要参与者,并通过将视图 objects 传递给控件并将控件传递给需要它的视图 objects 来将它们连接在一起:
import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
@SuppressWarnings("serial")
public class CoursesMainPanel extends JPanel {
public static final Color BACKGROUND = new Color(0xEED2CC);
public static final Color LABEL_FOREGROUND = new Color(0xA1683A);
private CoursesControl control = new CoursesControl();
private GetInfoPanel getInfoPanel = new GetInfoPanel();
private CourseTableModel tableModel = new CourseTableModel();
private TablePanel tablePanel = new TablePanel(tableModel);
public CoursesMainPanel() {
getInfoPanel.setControl(control);
control.setGetInfoPanel(getInfoPanel);
control.setTableModel(tableModel);
control.setTablePanel(tablePanel);
int gap = 2;
setLayout(new GridLayout(1, 2, gap, gap));
add(getInfoPanel);
add(tablePanel);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new CoursesMainPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
我会集中精力解决您眼前的问题,即在 class DisplayPanel
.
infoLabel
中显示文本
你有三个问题。第一个在 class MyPanel
.
MyPanel(DisplayPanel displayPanel) {
this.displayPanel = new DisplayPanel();
您正在忽略构造函数参数并创建 DisplayPanel
的新实例。因此,class MyPanel
的成员 displayPanel
与您在 class MainPanel
中创建的对象不同。因此,您在 DisplayPanel
上调用的方法是 而不是 添加到 MainPanel
。您需要将该行更改为以下内容。
MyPanel(DisplayPanel displayPanel) {
this.displayPanel = displayPanel;
第二个问题是您在 DisplayPanel
中设置了空布局。当没有 layout manager 时,您需要显式设置添加到 JPanel
的任何组件的边界。你没有这样做,因此你的 JLabel
没有显示。只需从 DisplayPanel
this.setLayout(null);
最后,在 class DisplayPanel
的方法 setLabelText
中,您只需通过方法 setText
更改 JLabel
文本。无需删除所有组件并再次添加它们。方法应该如下。
public void setLabelText(ArrayList<String> courseNames, ArrayList<Integer> courseCredits, ArrayList<Double> courseGrades) {
StringBuilder sb = new StringBuilder();
for (String name : courseNames) {
sb.append(name + "\t" + courseCredits.get(courseNames.indexOf(name)) + "\t" + courseGrades.get(courseNames.indexOf(name)));
}
infoLabel.setText(sb.toString());
}
编辑
如果我的任务是制作这个应用程序,我会做类似下面的事情。
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.text.ParseException;
import javax.swing.JButton;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableModel;
import javax.swing.text.MaskFormatter;
public class GpaCalcs implements Runnable {
private DefaultTableModel tableModel;
private JFormattedTextField courseCreditsTextField;
private JFormattedTextField gradeTextField;
private JFrame frame;
private JTable table;
private JTextField courseNameTextField;
public void run() {
try {
createAndDisplayGui();
}
catch (Exception x) {
throw new RuntimeException(x);
}
}
private void addCourse(ActionEvent event) {
Object[] row = new Object[3];
row[0] = courseNameTextField.getText();
row[1] = courseCreditsTextField.getValue();
row[2] = gradeTextField.getValue();
tableModel.addRow(row);
}
private void createAndDisplayGui() throws ParseException {
frame = new JFrame("GPA Calculator");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private void createButtonsPanel(JPanel formPanel, GridBagConstraints gbc) {
JPanel buttonsPanel = new JPanel();
JButton addCourseButton = new JButton("Add Course");
addCourseButton.addActionListener(this::addCourse);
buttonsPanel.add(addCourseButton);
JButton calcGpaButton = new JButton("Calculate GPA");
buttonsPanel.add(calcGpaButton);
JButton resetButton = new JButton("Reset");
resetButton.addActionListener(this::reset);
buttonsPanel.add(resetButton);
gbc.gridwidth = 3;
formPanel.add(buttonsPanel, gbc);
}
private JScrollPane createDisplayPanel() {
String[] columns = new String[]{"Course", "Credits", "Grade"};
tableModel = new DefaultTableModel(columns, 0);
table = new JTable(tableModel);
JScrollPane scrollPane = new JScrollPane(table);
return scrollPane;
}
private JPanel createFormPanel() throws ParseException {
JPanel formPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.LINE_START;
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets.bottom = 5;
gbc.insets.left = 5;
gbc.insets.right = 5;
gbc.insets.top = 5;
JLabel courseNameLabel = new JLabel("Course Name");
formPanel.add(courseNameLabel, gbc);
gbc.gridx = 1;
courseNameTextField = new JTextField(10);
formPanel.add(courseNameTextField, gbc);
gbc.gridx = 0;
gbc.gridy = 1;
JLabel courseCreditLabel = new JLabel("Course Credits (ECTS)");
formPanel.add(courseCreditLabel, gbc);
gbc.gridx = 1;
MaskFormatter formatter = new MaskFormatter("####"); // throws java.text.ParseException
courseCreditsTextField = new JFormattedTextField(formatter);
courseCreditsTextField.setColumns(10);
formPanel.add(courseCreditsTextField, gbc);
gbc.gridx = 0;
gbc.gridy = 2;
JLabel gradeLabel = new JLabel("Your Grade");
formPanel.add(gradeLabel, gbc);
gbc.gridx = 1;
formatter = new MaskFormatter("#.##");
gradeTextField = new JFormattedTextField(formatter);
gradeTextField.setColumns(10);
formPanel.add(gradeTextField, gbc);
gbc.gridx = 0;
gbc.gridy = 3;
createButtonsPanel(formPanel, gbc);
return formPanel;
}
private JPanel createMainPanel() throws ParseException {
JPanel mainPanel = new JPanel(new GridLayout(0, 2));
mainPanel.add(createFormPanel());
mainPanel.add(createDisplayPanel());
return mainPanel;
}
private void reset(ActionEvent event) {
courseNameTextField.setText("");
courseCreditsTextField.setText("");
gradeTextField.setText("");
}
public static void main(String[] args) {
EventQueue.invokeLater(new GpaCalcs());
}
}