Here is a clean, modular MVC (Model-View-Controller) implementation for a Student Database using Java Swing and a JTable.
This design separates the data (Model), the user interface (View), and the logic that connects them (Controller), making your code much easier to maintain and scale.
1. The Model
The model consists of two parts: the data object (Student) and the table model (StudentTableModel) that JTable uses to display the data.
Student.java
package model;
public class Student {
private int id;
private String name;
private String grade;
public Student(int id, String name, String grade) {
this.id = id;
this.name = name;
this.grade = grade;
}
// Getters and Setters
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getGrade() { return grade; }
public void setGrade(String grade) { this.grade = grade; }
}
StudentTableModel.java
package model;
import javax.swing.table.AbstractTableModel;
import java.util.ArrayList;
import java.util.List;
public class StudentTableModel extends AbstractTableModel {
private final String[] columnNames = {"ID", "Name", "Grade"};
private final List<Student> students;
public StudentTableModel() {
this.students = new ArrayList<>();
}
public void setStudents(List<Student> students) {
this.students.clear();
this.students.addAll(students);
fireTableDataChanged(); // Notifies the JTable to refresh
}
@Override
public int getRowCount() {
return students.size();
}
@Override
public int getColumnCount() {
return columnNames.length;
}
@Override
public String getColumnName(int column) {
return columnNames[column];
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Student student = students.get(rowIndex);
switch (columnIndex) {
case 0: return student.getId();
case 1: return student.getName();
case 2: return student.getGrade();
default: return null;
}
}
}
2. The View
The view handles the visual layout. It exposes methods to get input data and register button listeners without containing any business logic.
StudentView.java
package view;
import model.StudentTableModel;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
public class StudentView extends JFrame {
private JTable table;
private JTextField txtId, txtName, txtGrade;
private JButton btnAdd;
public StudentView(StudentTableModel tableModel) {
setTitle("Student Database (MVC)");
setSize(500, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setLayout(new BorderLayout());
// Table Setup
table = new JTable(tableModel);
add(new JScrollPane(table), BorderLayout.CENTER);
// Input Form Panel
JPanel inputPanel = new JPanel(new GridLayout(4, 2, 5, 5));
inputPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
inputPanel.add(new JLabel("ID:"));
txtId = new JTextField();
inputPanel.add(txtId);
inputPanel.add(new JLabel("Name:"));
txtName = new JTextField();
inputPanel.add(txtName);
inputPanel.add(new JLabel("Grade:"));
txtGrade = new JTextField();
inputPanel.add(txtGrade);
btnAdd = new JButton("Add Student");
inputPanel.add(new JLabel("")); // Empty placeholder
inputPanel.add(btnAdd);
add(inputPanel, BorderLayout.SOUTH);
}
// Getters for Form Data
public String getStudentId() { return txtId.getText(); }
public String getStudentName() { return txtName.getText(); }
public String getStudentGrade() { return txtGrade.getText(); }
// Clear form after adding
public void clearForm() {
txtId.setText("");
txtName.setText("");
txtGrade.setText("");
}
// Attach controller listener to button
public void addStudentListener(ActionListener listener) {
btnAdd.addActionListener(listener);
}
public void showMessage(String message) {
JOptionPane.showMessageDialog(this, message);
}
}
3. The Controller
The controller acts as the bridge. It listens for clicks in the View, updates the database/list, and tells the Model to update the UI.
StudentController.java
package controller;
import model.Student;
import model.StudentTableModel;
import view.StudentView;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
public class StudentController {
private StudentView view;
private StudentTableModel tableModel;
private List<Student> databaseMock; // Mimicking a database row set
public StudentController(StudentView view, StudentTableModel tableModel) {
this.view = view;
this.tableModel = tableModel;
this.databaseMock = new ArrayList<>();
// Load dummy data initially
databaseMock.add(new Student(101, "Alice Smith", "A"));
databaseMock.add(new Student(102, "Bob Jones", "B"));
tableModel.setStudents(databaseMock);
// Wire up the button listener
this.view.addStudentListener(new AddStudentButtonListener());
}
// Inner class to handle button clicks
private class AddStudentButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
try {
int id = Integer.parseInt(view.getStudentId());
String name = view.getStudentName();
String grade = view.getStudentGrade();
if (name.isEmpty() || grade.isEmpty()) {
view.showMessage("Please fill all fields.");
return;
}
// Update "Database"
databaseMock.add(new Student(id, name, grade));
// Push updated list to the Table Model
tableModel.setStudents(databaseMock);
// Reset View
view.clearForm();
} catch (NumberFormatException ex) {
view.showMessage("Please enter a valid numeric ID.");
}
}
}
}
4. Application Entry Point
The Main class ties all the components together.
Main.java
import controller.StudentController;
import model.StudentTableModel;
import view.StudentView;
import javax.swing.SwingUtilities;
public class Main {
public static void main(String[] args) {
// Run UI creation on the Event Dispatch Thread (EDT)
SwingUtilities.invokeLater(() -> {
// 1. Initialize Model
StudentTableModel tableModel = new StudentTableModel();
// 2. Initialize View and pass the Model to it
StudentView view = new StudentView(tableModel);
// 3. Initialize Controller to bridge View and Data
new StudentController(view, tableModel);
// 4. Show the application
view.setVisible(true);
});
}
}
Highlights of this setup:
Decoupled Logic: The
StudentViewdoesn't know what happens when the button is clicked; it just delegates that responsibility to the controller.Dynamic Table Updates: By extending
AbstractTableModeland callingfireTableDataChanged(), theJTableautomatically refreshes its view whenever the underlying list changes.
Tidak ada komentar:
Posting Komentar