【Swingアプリ開発】学生情報管理システム(簡易版)の解答例

2025-08-06

以下は、Swingを使用した学生情報管理システムの完全な実装例です。学生情報の追加、編集、削除、一覧表示機能を備えています。

import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class StudentManagementSystem {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            // メインウィンドウの作成
            JFrame frame = new JFrame("学生情報管理システム");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setSize(900, 600);

            // 学生データを保持するリスト
            List students = new ArrayList<>();
            loadStudentData(students); // 起動時にデータを読み込む

            // テーブルモデルの作成
            StudentTableModel tableModel = new StudentTableModel(students);
            JTable table = new JTable(tableModel);
            table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            JScrollPane scrollPane = new JScrollPane(table);

            // ボタンパネルの作成
            JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
            JButton addButton = new JButton("追加");
            JButton editButton = new JButton("編集");
            JButton deleteButton = new JButton("削除");
            JButton saveButton = new JButton("保存");

            // ボタンにアクションを追加
            addButton.addActionListener(e -> {
                StudentDialog dialog = new StudentDialog(frame, "学生情報の追加", null);
                if (dialog.showDialog()) {
                    students.add(dialog.getStudent());
                    tableModel.fireTableDataChanged();
                }
            });

            editButton.addActionListener(e -> {
                int selectedRow = table.getSelectedRow();
                if (selectedRow >= 0) {
                    Student selectedStudent = students.get(selectedRow);
                    StudentDialog dialog = new StudentDialog(frame, "学生情報の編集", selectedStudent);
                    if (dialog.showDialog()) {
                        students.set(selectedRow, dialog.getStudent());
                        tableModel.fireTableDataChanged();
                    }
                } else {
                    JOptionPane.showMessageDialog(frame, 
                        "編集する学生を選択してください", 
                        "警告", 
                        JOptionPane.WARNING_MESSAGE);
                }
            });

            deleteButton.addActionListener(e -> {
                int selectedRow = table.getSelectedRow();
                if (selectedRow >= 0) {
                    int confirm = JOptionPane.showConfirmDialog(frame, 
                        "選択した学生を削除しますか?", 
                        "確認", 
                        JOptionPane.YES_NO_OPTION);
                    if (confirm == JOptionPane.YES_OPTION) {
                        students.remove(selectedRow);
                        tableModel.fireTableDataChanged();
                    }
                } else {
                    JOptionPane.showMessageDialog(frame, 
                        "削除する学生を選択してください", 
                        "警告", 
                        JOptionPane.WARNING_MESSAGE);
                }
            });

            saveButton.addActionListener(e -> {
                saveStudentData(students);
                JOptionPane.showMessageDialog(frame, 
                    "データを保存しました", 
                    "情報", 
                    JOptionPane.INFORMATION_MESSAGE);
            });

            // ボタンをパネルに追加
            buttonPanel.add(addButton);
            buttonPanel.add(editButton);
            buttonPanel.add(deleteButton);
            buttonPanel.add(saveButton);

            // メインウィンドウにコンポーネントを追加
            frame.add(scrollPane, BorderLayout.CENTER);
            frame.add(buttonPanel, BorderLayout.SOUTH);

            frame.setVisible(true);
        });
    }

    // 学生データをファイルから読み込む
    private static void loadStudentData(List students) {
        File file = new File("students.dat");
        if (file.exists()) {
            try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) {
                List loadedStudents = (List) ois.readObject();
                students.clear();
                students.addAll(loadedStudents);
            } catch (Exception ex) {
                ex.printStackTrace();
                JOptionPane.showMessageDialog(null, 
                    "データの読み込みに失敗しました", 
                    "エラー", 
                    JOptionPane.ERROR_MESSAGE);
            }
        }
    }

    // 学生データをファイルに保存
    private static void saveStudentData(List students) {
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("students.dat"))) {
            oos.writeObject(students);
        } catch (IOException ex) {
            ex.printStackTrace();
            JOptionPane.showMessageDialog(null, 
                "データの保存に失敗しました", 
                "エラー", 
                JOptionPane.ERROR_MESSAGE);
        }
    }
}

// 学生情報を表すクラス(シリアライズ可能)
class Student implements Serializable {
    private String studentId;
    private String name;
    private String department;
    private int grade;
    private String email;

    public Student(String studentId, String name, String department, int grade, String email) {
        this.studentId = studentId;
        this.name = name;
        this.department = department;
        this.grade = grade;
        this.email = email;
    }

    // ゲッターとセッター
    public String getStudentId() { return studentId; }
    public String getName() { return name; }
    public String getDepartment() { return department; }
    public int getGrade() { return grade; }
    public String getEmail() { return email; }

    public void setStudentId(String studentId) { this.studentId = studentId; }
    public void setName(String name) { this.name = name; }
    public void setDepartment(String department) { this.department = department; }
    public void setGrade(int grade) { this.grade = grade; }
    public void setEmail(String email) { this.email = email; }
}

// テーブルモデルの実装
class StudentTableModel extends AbstractTableModel {
    private final List students;
    private final String[] columnNames = {"学籍番号", "氏名", "学部", "学年", "メールアドレス"};

    public StudentTableModel(List students) {
        this.students = students;
    }

    @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.getStudentId();
            case 1: return student.getName();
            case 2: return student.getDepartment();
            case 3: return student.getGrade();
            case 4: return student.getEmail();
            default: return null;
        }
    }

    public Student getStudentAt(int rowIndex) {
        return students.get(rowIndex);
    }
}

// 学生情報編集ダイアログ
class StudentDialog extends JDialog {
    private boolean approved = false;
    private Student student;

    private JTextField idField;
    private JTextField nameField;
    private JComboBox departmentCombo;
    private JSpinner gradeSpinner;
    private JTextField emailField;

    public StudentDialog(Frame owner, String title, Student student) {
        super(owner, title, true);
        setSize(400, 300);
        setLocationRelativeTo(owner);

        this.student = (student == null) ? 
            new Student("", "", "情報学部", 1, "") : 
            new Student(student.getStudentId(), student.getName(), 
                       student.getDepartment(), student.getGrade(), student.getEmail());

        // フォームコンポーネントの作成
        idField = new JTextField(this.student.getStudentId(), 15);
        nameField = new JTextField(this.student.getName(), 15);

        String[] departments = {"情報学部", "経済学部", "文学部", "理学部", "工学部"};
        departmentCombo = new JComboBox<>(departments);
        departmentCombo.setSelectedItem(this.student.getDepartment());

        gradeSpinner = new JSpinner(new SpinnerNumberModel(this.student.getGrade(), 1, 4, 1));
        emailField = new JTextField(this.student.getEmail(), 15);

        // レイアウト設定
        JPanel formPanel = new JPanel(new GridLayout(5, 2, 10, 10));
        formPanel.add(new JLabel("学籍番号:"));
        formPanel.add(idField);
        formPanel.add(new JLabel("氏名:"));
        formPanel.add(nameField);
        formPanel.add(new JLabel("学部:"));
        formPanel.add(departmentCombo);
        formPanel.add(new JLabel("学年:"));
        formPanel.add(gradeSpinner);
        formPanel.add(new JLabel("メールアドレス:"));
        formPanel.add(emailField);

        // ボタンパネル
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        JButton okButton = new JButton("OK");
        JButton cancelButton = new JButton("キャンセル");

        okButton.addActionListener(e -> {
            approved = true;
            updateStudent();
            dispose();
        });

        cancelButton.addActionListener(e -> dispose());

        buttonPanel.add(okButton);
        buttonPanel.add(cancelButton);

        // ダイアログにコンポーネントを追加
        setLayout(new BorderLayout(10, 10));
        add(formPanel, BorderLayout.CENTER);
        add(buttonPanel, BorderLayout.SOUTH);
    }

    private void updateStudent() {
        student.setStudentId(idField.getText());
        student.setName(nameField.getText());
        student.setDepartment((String)departmentCombo.getSelectedItem());
        student.setGrade((Integer)gradeSpinner.getValue());
        student.setEmail(emailField.getText());
    }

    public boolean showDialog() {
        setVisible(true);
        return approved;
    }

    public Student getStudent() {
        return student;
    }
}

この学生情報管理システムの特徴

  1. 基本機能:
  • 学生情報の追加、編集、削除
  • 一覧表示(テーブル形式)
  • データの永続化(ファイル保存・読み込み)
  1. UI構成:
  • メイン画面に学生一覧テーブル
  • 下部に操作ボタン(追加、編集、削除、保存)
  • 学生情報編集用のカスタムダイアログ
  1. 技術的特徴:
  • AbstractTableModelを継承したカスタムテーブルモデル
  • シリアライズを使用したデータ永続化
  • MVC(Model-View-Controller)に準拠した設計

拡張可能なポイント

この基本実装をさらに発展させるためのアイデア:

  1. 追加機能:
  • 検索/フィルタリング機能
  • 成績管理の追加
  • 統計情報の表示(グラフなど)
  • CSV/Excel形式でのインポート/エクスポート
  1. UI改善:
  • テーブルのソート機能
  • バリデーションの強化
  • レスポンシブなレイアウト
  1. コードの改良:
  • コントローラクラスの導入
  • データアクセス層の分離
  • イベントバスを使用したコンポーネント間通信

例えば、検索機能を追加するには:

// 検索パネルを追加
JPanel searchPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
JTextField searchField = new JTextField(20);
JButton searchButton = new JButton("検索");
searchPanel.add(new JLabel("検索:"));
searchPanel.add(searchField);
searchPanel.add(searchButton);

// メインウィンドウに検索パネルを追加(NORTH領域)
frame.add(searchPanel, BorderLayout.NORTH);

// 検索ボタンのアクション
searchButton.addActionListener(e -> {
    String keyword = searchField.getText().toLowerCase();
    if (keyword.isEmpty()) {
        // キーワードが空の場合は全件表示
        tableModel.fireTableDataChanged();
    } else {
        // 検索実行(学籍番号、氏名、メールアドレスで部分一致)
        List filtered = new ArrayList<>();
        for (Student s : students) {
            if (s.getStudentId().toLowerCase().contains(keyword) ||
                s.getName().toLowerCase().contains(keyword) ||
                s.getEmail().toLowerCase().contains(keyword)) {
                filtered.add(s);
            }
        }
        // フィルタリングされたデータで新しいテーブルモデルを作成
        StudentTableModel filteredModel = new StudentTableModel(filtered);
        table.setModel(filteredModel);
    }
});

この学生情報管理システムは、Swingを使った実践的なアプリケーション開発の良い例です。基本機能を理解した後、必要に応じて機能を拡張していくことで、より実用的なシステムに発展させることができます。