Senin, 13 Juli 2026

JAVA MVC 1

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

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

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

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

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

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 StudentView doesn't know what happens when the button is clicked; it just delegates that responsibility to the controller.

  • Dynamic Table Updates: By extending AbstractTableModel and calling fireTableDataChanged(), the JTable automatically refreshes its view whenever the underlying list changes.






Main.java
/*
 * 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 Controller;
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);
        });
    }
}
==================================================================

StudentController.java
/*
 * 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 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.");
            }
        }
    }
}
============================================

Student.java
/*
 * 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 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
/*
 * 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 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;
        }
    }
}

==========================================
StudentView.java
/*
 * 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 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);
    }
}



Tidak ada komentar: