Полезное для программистов:

Фриланс
Новости
Статьи
   
Рубрики:


Часть 6 - GUI - заключительные классы

Поиск:
Окончание работы с GUI

Для окончательного вида нам необходимо сделать еще три вещи:
- Сделать диалоговое окно для ввода данных при перемещении студентов из одной группы в другую
- Сделать диалог для ввода данных для студента
- Сделать форму для вывода отчета по всем студентам

Давайте начнем с формы для перемещения студентов из группы в группу.
Сама по себе форма не сложная - просто посмотрим код для класса и после этого код для вызова этой формы и реализации команды.

Итак - наш новый класс GroupDialog.java
Самое главное находится в его конструкторе - тут мы создаем все необходимые элементы - выпадающий список для групп и спинер для года. Также обратите внимание на то, как мы обрабатываем нажатие кнопок - ловим событие листенером и устанавливаем внутреннее поле result в true или false.
Если объявить result как int, то по идее можно устанавливать фактически любое количество возможных результатов - т.е. любая кнопка может закрыть окно и можно потом проверить, какая конкретно была нажата.

Кроме этого мы воспользовались достаточно сложным kayout'ом - GridBagLayout. 
РекомендуемВы можете почитать о нем в статье "Что такое LayoutManager" - http://vingrad.ru/JAVA-JAV-000105

Итак, наш новый класс GroupDialog.java
Код

package students.frame;

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;

import students.logic.Group;

public class GroupDialog extends JDialog implements ActionListener
{
  private static final int D_HEIGHT = 150;   // высота
  private final static int D_WIDTH = 200;   // ширина
  
  private JSpinner spYear;
  private JComboBox groupList;
  private JButton btnOk = new JButton("OK");
  private JButton btnCancel = new JButton("Cancel");
  
  private boolean result = false;
  
  public GroupDialog(int year, List groups)
  {
    // Установить заголовок
    setTitle("Перенос группы");
    
    // Создаем сложный layout для нашего окна
    GridBagLayout gbl = new GridBagLayout();
    setLayout(gbl);
    // Создаем переменную для установки правил размещения 
    GridBagConstraints c = new GridBagConstraints();
    // Сразу задаем отступ от границ для каждого элемента
    c.insets = new Insets(5,5,5,5);

    // Первый элемент - заголовок для поля выбора групп
    JLabel l = new JLabel("Новая группа:");
    // После него можно будет еще помещать компоненты
    c.gridwidth = GridBagConstraints.RELATIVE;
    // Не заполняем все пространство, отведенное компоненту
    c.fill = GridBagConstraints.NONE;
    // "Привязываем" компонент к правому краю
    c.anchor = GridBagConstraints.EAST;
    // Устанавливаем это правило для нашего компонета
    gbl.setConstraints(l, c);
    // Добавляем компонент
    getContentPane().add(l);

    // Второй элемент - список групп
    groupList = new JComboBox(new Vector(groups));
    // Элемент занимает всю оставшуюся ширину
    c.gridwidth = GridBagConstraints.REMAINDER;
    // Растягиваем компонент по всему пространству для него
    c.fill = GridBagConstraints.BOTH;
    // "Привязываем" его к левой части
    c.anchor = GridBagConstraints.WEST;
    // Устанавливаем это правило для нашего компонета
    gbl.setConstraints(groupList, c);
    // Добавляем компонент
    getContentPane().add(groupList);
    
    // Третий элемент - заголовок для поля выбора года
    l = new JLabel("Новый год:");
    // После него можно будет еще помещать компоненты
    c.gridwidth = GridBagConstraints.RELATIVE;
    // Не заполняем все пространство, отведенное компоненту
    c.fill = GridBagConstraints.NONE;
    // "Привязываем" компонент к правому краю
    c.anchor = GridBagConstraints.EAST;
    // Устанавливаем это правило для нашего компонета
    gbl.setConstraints(l, c);
    // Добавляем компонент
    getContentPane().add(l);
    
    // Сразу увеличиваем группу на один год - для перевода
    spYear = new JSpinner(new SpinnerNumberModel(year+1, 1900, 2100, 1));
    // Элемент занимает всю оставшуюся ширину
    c.gridwidth = GridBagConstraints.REMAINDER;
    // Растягиваем компонент по всему пространству для него
    c.fill = GridBagConstraints.BOTH;
    // "Привязываем" его к левой части
    c.anchor = GridBagConstraints.WEST;
    // Устанавливаем это правило для нашего компонета
    gbl.setConstraints(spYear, c);
    // Добавляем компонент
    getContentPane().add(spYear);
    
    c.gridwidth = GridBagConstraints.RELATIVE;
    c.fill = GridBagConstraints.BOTH;
    btnOk.setName("OK");
    // Добавляем листенер для кнопки
    btnOk.addActionListener(this);
    // Устанавливаем это правило для нашего компонета
    gbl.setConstraints(btnOk, c);
    // Добавляем компонент
    getContentPane().add(btnOk);

    btnCancel.setName("Cancel");
    // Добавляем листенер для кнопки
    btnCancel.addActionListener(this);
    // Устанавливаем это правило для нашего компонета
    gbl.setConstraints(btnCancel, c);
    // Добавляем компонент
    getContentPane().add(btnCancel);

    // Устанавливаем поведение формы при закрытии - не закрывать совсем.
    setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
    
    // Получаем размеры экрана
    Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
    // А теперь просто помещаем его по центру, вычисляя координаты на основе полученной информации
    setBounds(((int)d.getWidth() - GroupDialog.D_WIDTH) / 2, ((int)d.getHeight() - GroupDialog.D_HEIGHT) / 2, 
        GroupDialog.D_WIDTH, GroupDialog.D_HEIGHT);  
  }
  
  // Возврат года, который установлен на форме
  public int getYear()
  {
    return ((SpinnerNumberModel)spYear.getModel()).getNumber().intValue();
  }

  // Возврат группы, которая установлена на форме
  public Group getGroup()
  {
    if(groupList.getModel().getSize()>0) {
      return (Group)groupList.getSelectedItem(); 
    }
    return null;
  }
  
  // Получить результат, true - кнопка ОК, false - кнопка Cancel 
  public boolean getResult()
  {
    return result;
  }

  // Обработка нжатия кнопок
  public void actionPerformed(ActionEvent e)
  {
    JButton src = (JButton)e.getSource();
    if(src.getName().equals("OK")) {
      result = true;
    }
    if(src.getName().equals("Cancel")) {
      result = false;
    }
    setVisible(false);
  }
}


Пока не будем приводить полностью код StudentsFrame. Покажем только наш новый вариант метода moveGroup
Код

  // метод для переноса группы
  private void moveGroup()
  {
    Thread t = new Thread() {
      public void run()
      {
        // Если группа не выделена - выходим. Хотя это крайне маловероятно
        if (grpList.getSelectedValue() == null) {
          return;
        }
        try {
          // Получаем выделенную группу
          Group g = (Group) grpList.getSelectedValue();
          // Получаем число из спинера
          int y = ((SpinnerNumberModel) spYear.getModel()).getNumber()
              .intValue();
          // Создаем наш диалог
          GroupDialog gd = new GroupDialog(y, ms.getGroups());
          // Задаем ему режим модальности - нельзя ничего кроме него выделить
          gd.setModal(true);
          // Показываем диалог
          gd.setVisible(true);
          // Если нажали кнопку OK - перемещаем в новую группу с новым годом
          // и перегружаем список студентов
          if (gd.getResult()) {
            ms.moveStudentsToGroup(g, y, gd.getGroup(), gd.getYear());
            reloadStudents();
          }
        } catch (SQLException e) {
          JOptionPane.showMessageDialog(StudentsFrame.this, e.getMessage());
        }
      }
    };
    t.start();
  }


Теперь посмотрим, каким образом нам сделать класс для редактирования данных о студенте. Этот класс может служить как для добавления так и для редактирования - поля будут одинаковые.
Отметим, что ИД студента должно где-то храниться и если этот ИД будет больше 0 - это может служить нам знаком, что студента надо редактировать - т.е. выполнить обновление данных. Если же ИД равен 0, то это значит, что данные надо будет добавить. Хотя в нашей реализации данный момент мы использовать не будем. Просто для хранения остальных полей можно использовать визуальные компоненты. А для ИД надо будет ввести дополнительное поле.
Также у нас есть два варината передачи данных:
- Передавать отдельно по всем полям, т.е. разбивать данные о студенте на строки, цифры и даты и передавать каждое поле отдельно своим сеттером и геттером
- Передавать сразу всего студента целиком как экземпляр класса и получать его также

Мы выберем второй способ. Первый может быть привлекателен только если мы хотим сделать некое универсальное окно, которое потом использовать в других проектах. Но я думаю, что это больше затруднит нам работу. Количество методов будет велико и, на мой взгляд, не оправдано.

Т.е. мы сделаем два метода setStudent/getStudent. setStudent распределит данные о студенте по всем полям, а getStudent соберет данные со всех полей и отдаст нам уже готовый экземпляр типа Student. Значение поля StudentId в экземпляре Student скажет нам, добавлять нам нового студента или изменить данные о существующем.

Также необходимо отметить, что нам потребуется конструктор для класса Student - сейчас он конструируется прямо из ResultSet. Нам же необходимо сделать конструктор без параметров. Он вообщем-то совсем ничего не делает, но правила языка требуют.

Мы ранее упоминали, что при добавлении студента программа будет позволять добавлять студента без закрытия окна - это удобно, когда набирают данные о новой группе. В этом случае мы оставляем данне о группе и годе такими же, а остальыне данные стираем.
Всего у нас будет 7 полей:
- Три обычных тескстовых поля - Фамилия, Имя, отчество
- Спинер для выбора даты рожения - не очень он мне нравится, но Вы можете его исправить до того, чтобы Вам хотелось
- Радио-кнопки для выбора пола - муж/жен
- Выпадающий список с группами
- Спинер для выбора года обучения

Автор не претендует на высокий уровень дизайна данного окна - возможно специалисты по GUI выявят много недостатков. Моя цель показать возможности GUI - так что Вы можете самостоятельно подправить неудачные места.

Кроме этого отметим, что нам необходимо будет перегружать данные о студентах не выходя из диалогового окна - значит нам во-первых потребуется сделать метод StudentsFrame.reloadStudents() доступным (public). И также мы в конструкторе передаем ссылку на главную форму StudentsFrame чтобы можно было вызвать данный метод

Итак, вот наш класс для ввода данных для студента.
Код

package students.frame;

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.Vector;

import javax.swing.AbstractButton;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JRadioButton;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerDateModel;
import javax.swing.SpinnerNumberModel;

import students.logic.Group;
import students.logic.ManagementSystem;
import students.logic.Student;

public class StudentDialog extends JDialog implements ActionListener
{
  private static final int D_HEIGHT = 200;   // высота окна
  private final static int D_WIDTH = 450;   // ширина окна
  
  private final static int L_X = 10;      // левая граница метки для поля
  private final static int L_W = 100;     // ширина метки для поля
  private final static int C_W = 150;     // ширина поля

  // Владелец нашего окна - вводим для вызова нужного нам метода
  private StudentsFrame owner;
  // Результат нажатия кнопок
  private boolean result = false;
  
  // Параметры студента 
  private int studentId = 0;
  private JTextField firstName = new JTextField();
  private JTextField surName = new JTextField();
  private JTextField patronymic = new JTextField();
  private JSpinner dateOfBirth = new JSpinner(new SpinnerDateModel(new Date(),null, null, Calendar.DAY_OF_MONTH));
  private ButtonGroup sex = new ButtonGroup();
  private JSpinner year = new JSpinner(new SpinnerNumberModel(2006, 1900, 2100, 1));
  private JComboBox groupList;

  // Второй параметр содержит знак - добавление студента или исправление
  public StudentDialog(List groups, boolean newStudent, StudentsFrame owner)
  {
    // После вставки студента без закрытия окна нам потребуется перегрузка списка
    // А для этого нам надо иметь доступ к этому методу в главной форме
    this.owner = owner;
    // Установить заголовок
    setTitle("Редактирование данных студента");
    getContentPane().setLayout(new FlowLayout());

    groupList = new JComboBox(new Vector(groups));
    
    JRadioButton m = new JRadioButton("Муж");
    JRadioButton w = new JRadioButton("Жен");
    // Сделаем имя такое же, как требуется в баще данных - М/Ж
    m.setActionCommand("М");
    w.setActionCommand("Ж");
    // Добавим радио-кнопки в группу
    sex.add(m);
    sex.add(w);
    
    // Не будем использовать layout совсем
    getContentPane().setLayout(null);
    
    // Разместим компоненты по абсолютным координатам
    // Фамилия
    JLabel l = new JLabel("Фамилия:", JLabel.RIGHT);
    l.setBounds(L_X, 10, L_W, 20);
    getContentPane().add(l);
    surName.setBounds(L_X+L_W+10, 10, C_W, 20);
    getContentPane().add(surName);
    // Имя
    l = new JLabel("Имя:", JLabel.RIGHT);
    l.setBounds(L_X, 30, L_W, 20);
    getContentPane().add(l);
    firstName.setBounds(L_X+L_W+10, 30, C_W, 20);
    getContentPane().add(firstName);
    // Отчество
    l = new JLabel("Отчество:", JLabel.RIGHT);
    l.setBounds(L_X, 50, L_W, 20);
    getContentPane().add(l);
    patronymic.setBounds(L_X+L_W+10, 50, C_W, 20);
    getContentPane().add(patronymic);
    // Пол
    l = new JLabel("Пол:", JLabel.RIGHT);
    l.setBounds(L_X, 70, L_W, 20);
    getContentPane().add(l);
    m.setBounds(L_X+L_W+10, 70, C_W/2, 20);
    getContentPane().add(m);
    // Сделаем по умолчанию женщину - из уважения
    w.setBounds(L_X+L_W+10+C_W/2, 70, C_W/2, 20);
    w.setSelected(true);
    getContentPane().add(w);
    // Дата рождения
    l = new JLabel("Дата рождения:", JLabel.RIGHT);
    l.setBounds(L_X, 90, L_W, 20);
    getContentPane().add(l);
    dateOfBirth.setBounds(L_X+L_W+10, 90, C_W, 20);
    getContentPane().add(dateOfBirth);
    // Группа
    l = new JLabel("Группа:", JLabel.RIGHT);
    l.setBounds(L_X, 115, L_W, 25);
    getContentPane().add(l);
    groupList.setBounds(L_X+L_W+10, 115, C_W, 25);
    getContentPane().add(groupList);
    // Год обучения
    l = new JLabel("Год обучения:", JLabel.RIGHT);
    l.setBounds(L_X, 145, L_W, 20);
    getContentPane().add(l);
    year.setBounds(L_X+L_W+10, 145, C_W, 20);
    getContentPane().add(year);
    
    JButton btnOk = new JButton("OK");
    btnOk.setName("OK");
    btnOk.addActionListener(this);
    btnOk.setBounds(L_X+L_W+C_W+10+50, 10, 100, 25);
    getContentPane().add(btnOk);
    
    JButton btnCancel = new JButton("Cancel");
    btnCancel.setName("Cancel");
    btnCancel.addActionListener(this);
    btnCancel.setBounds(L_X+L_W+C_W+10+50, 40, 100, 25);
    getContentPane().add(btnCancel);
    
    if(newStudent) {
      JButton btnNew = new JButton("New");
      btnNew.setName("New");
      btnNew.addActionListener(this);
      btnNew.setBounds(L_X+L_W+C_W+10+50, 70, 100, 25);
      getContentPane().add(btnNew);
    }
    
    // Устанавливаем поведение формы при закрытии - не закрывать совсем.
    setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
    
    // Получаем размеры экрана
    Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
    // А теперь просто помещаем его по центру, вычисляя координаты на основе полученной информации
    setBounds(((int)d.getWidth() - StudentDialog.D_WIDTH) / 2, ((int)d.getHeight() - StudentDialog.D_HEIGHT) / 2, 
        StudentDialog.D_WIDTH, StudentDialog.D_HEIGHT);  
  }

  // Установить поля соответственно переданным данным о студенте
  public void setStudent(Student st)
  {
    studentId = st.getStudentId();
    firstName.setText(st.getFirstName());
    surName.setText(st.getSurName());
    patronymic.setText(st.getPatronymic());
    dateOfBirth.getModel().setValue(st.getDateOfBirth());
    for(Enumeration e=sex.getElements(); e.hasMoreElements(); ) {
      AbstractButton ab = (AbstractButton)e.nextElement();
      ab.setSelected(ab.getActionCommand().equals(new String(""+st.getSex())));
    }
    year.getModel().setValue(new Integer(st.getEducationYear()));
    for(int i=0; i<groupList.getModel().getSize(); i++) {
      Group g = (Group)groupList.getModel().getElementAt(i);
      if(g.getGroupId()==st.getGroupId()) {
        groupList.setSelectedIndex(i);
        break;
      }
    }
  }

  // Вернуть данные в виде нового студента с соотвтествующими полями
  public Student getStudent()
  {
    Student st = new Student();
    st.setStudentId(studentId);
    st.setFirstName(firstName.getText());
    st.setSurName(surName.getText());
    st.setPatronymic(patronymic.getText());
    Date d = ((SpinnerDateModel)dateOfBirth.getModel()).getDate();
    st.setDateOfBirth(d);
    for(Enumeration e=sex.getElements(); e.hasMoreElements(); ) {
      AbstractButton ab = (AbstractButton)e.nextElement();
      if(ab.isSelected()) {
        st.setSex(ab.getActionCommand().charAt(0));
      }
    }
    int y = ((SpinnerNumberModel)year.getModel()).getNumber().intValue();
    st.setEducationYear(y);
    st.setGroupId(((Group)groupList.getSelectedItem()).getGroupId());
    return st;
  }
  
  // Получить результат, true - кнопка ОК, false - кнопка Cancel 
  public boolean getResult()
  {
    return result;
  }
  
  public void actionPerformed(ActionEvent e)
  {
    JButton src = (JButton)e.getSource();
    // Добавляем студента, но не закрываем окно
    // Здесь мы не будем вызывать в отдельном потоке сохранение. 
    // Оно не занимаем много времени и лишние действия здесь не оправданы
    if(src.getName().equals("New")) {
      result = true;
      try {
        ManagementSystem.getInstance().insertStudent(getStudent());
        owner.reloadStudents();
        firstName.setText("");
        surName.setText("");
        patronymic.setText("");
      } catch (SQLException sql_e) {
        JOptionPane.showMessageDialog(this, sql_e.getMessage());
      }
      return;
    }
    if(src.getName().equals("OK")) {
      result = true;
    }
    if(src.getName().equals("Cancel")) {
      result = false;
    }
    setVisible(false);
  }
}


Также покажем наши обновленные методы insertStudent() и updateStudent() в классе StudentsFrame
Код

  // метод для добавления студента
  private void insertStudent()
  {
    Thread t = new Thread() {
      public void run()
      {
        try {
          // Добавляем нового студента - поэтому true
          // Также заметим, что необходимо указать не просто this, а StudentsFrame.this
          // Иначе класс не будет воспринят - он же другой - анонимный
          StudentDialog sd = new StudentDialog(ms.getGroups(), true, StudentsFrame.this);
          sd.setModal(true);
          sd.setVisible(true);
          if (sd.getResult()) {
            Student s = sd.getStudent();
            ms.insertStudent(s);
            reloadStudents();
          }
        } catch (SQLException e) {
          JOptionPane.showMessageDialog(StudentsFrame.this, e.getMessage());
        }
      }
    };
    t.start();
  }

  // метод для редактирования студента
  private void updateStudent()
  {
    Thread t = new Thread() {
      public void run()
      {
        if (stdList != null) {
          StudentTableModel stm = (StudentTableModel) stdList.getModel();
          // Проверяем - выделен ли хоть какой-нибудь студент
          if (stdList.getSelectedRow() >= 0) {
            // Вот где нам пригодился метод getStudent(int rowIndex)
            Student s = stm.getStudent(stdList.getSelectedRow());
            try {
              // Исправляем данные на студента - поэтому false
              // Также заметим, что необходимо указать не просто this, а StudentsFrame.this
              // Иначе класс не будет воспринят - он же другой - анонимный
              StudentDialog sd = new StudentDialog(ms.getGroups(), false, StudentsFrame.this);
              sd.setStudent(s);
              sd.setModal(true);
              sd.setVisible(true);
              if (sd.getResult()) {
                Student us = sd.getStudent();
                ms.updateStudent(us);
                reloadStudents();
              }
            } catch (SQLException e) {
              JOptionPane.showMessageDialog(StudentsFrame.this, e.getMessage());
            }
          }
          // Если студент не выделен - сообщаем пользователю, что это необходимо
          else {
            JOptionPane.showMessageDialog(StudentsFrame.this,
                "Необходимо выделить студента в списке");
          }
        }
      }
    };
    t.start();
  }


Теперь нам осталось сделать только форму для показа полного списка студентов. И этот момент мне бы хотелось оставить Вам для самостоятельного изучения. Если Вам очень захочется узнать, как это надо сделать - пишите свои отзывы. И если их будет много - я что-нибудь придумаю. А теперь как обычно полный текст всех наших классов.

Student.java
Код

package students.logic;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.DateFormat;
import java.util.Date;


public class Student implements Comparable
{
    private int studentId;
    private String firstName;
    private String surName;
    private String patronymic;
    private Date dateOfBirth;
    private char sex;
    private int groupId;
    private int educationYear;

    public Student(ResultSet rs) throws SQLException
    {
      setStudentId(rs.getInt("student_id"));
      setFirstName(rs.getString("firstName"));
      setPatronymic(rs.getString("surName"));
      setSurName(rs.getString("patronymic"));
      setSex(rs.getString("sex").charAt(0));
      setDateOfBirth(rs.getDate("dateOfBirth"));
      setGroupId(rs.getInt("group_id"));
      setEducationYear(rs.getInt("educationYear"));
    }

    public Student()
    {
      
    }
    
    public Date getDateOfBirth()
    {
      return dateOfBirth;
    }

    public void setDateOfBirth(Date dateOfBirth)
    {
      this.dateOfBirth = dateOfBirth;
    }

    public int getEducationYear()
    {
      return educationYear;
    }

    public void setEducationYear(int educationYear)
    {
      this.educationYear = educationYear;
    }

    public int getGroupId()
    {
      return groupId;
    }

    public void setGroupId(int groupId)
    {
      this.groupId = groupId;
    }

    public int getStudentId()
    {
      return studentId;
    }

    public void setStudentId(int studentId)
    {
      this.studentId = studentId;
    }

    public String getFirstName()
    {
      return firstName;
    }

    public void setFirstName(String firstName)
    {
      this.firstName = firstName;
    }

    public String getPatronymic()
    {
      return patronymic;
    }

    public void setPatronymic(String patronymic)
    {
      this.patronymic = patronymic;
    }

    public String getSurName()
    {
      return surName;
    }

    public void setSurName(String surName)
    {
      this.surName = surName;
    }

    public char getSex()
    {
      return sex;
    }

    public void setSex(char sex)
    {
      this.sex = sex;
    }

    public String toString()
    {
      return surName
        + " "
        + firstName
        + " "
        + patronymic
        + ", "
        + DateFormat.getDateInstance(DateFormat.SHORT).format(
          dateOfBirth) + ", Группа ИД=" + groupId+ " Год:"+educationYear;
    }

    public int compareTo(Object obj)
    {
      return this.toString().compareTo(obj.toString());
    }
}


Group.java
Код

package students.logic;

public class Group
{
    private int groupId;
    private String nameGroup;
    private String curator;
    private String speciality;

    public String getCurator()
    {
      return curator;
    }

    public void setCurator(String curator)
    {
      this.curator = curator;
    }

    public int getGroupId()
    {
      return groupId;
    }

    public void setGroupId(int groupId)
    {
      this.groupId = groupId;
    }

    public String getNameGroup()
    {
      return nameGroup;
    }

    public void setNameGroup(String nameGroup)
    {
      this.nameGroup = nameGroup;
    }

    public String getSpeciality()
    {
      return speciality;
    }

    public void setSpeciality(String speciality)
    {
      this.speciality = speciality;
    }

    public String toString()
    {
      return nameGroup;
    }
}


ManagementSystem.java
Код

package students.logic;

import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class ManagementSystem
{
  private static Connection con; 
  private static ManagementSystem instance;

  private ManagementSystem() {
    try {
      Class.forName("com.mysql.jdbc.Driver");
      String url = "jdbc:mysql://localhost/students";
      con = DriverManager.getConnection(url,"root", "");
    } catch (ClassNotFoundException e1) {
      e1.printStackTrace();
    } catch (SQLException e) {
      e.printStackTrace();
    }
  }

  public static synchronized ManagementSystem getInstance()
  {
    if (instance == null) {
      instance = new ManagementSystem();
    }
    return instance;
  }

  public List getGroups() throws SQLException
  {
    List groups = new ArrayList();
    
    Statement stmt = con.createStatement();
    ResultSet rs = stmt.executeQuery("SELECT group_id, groupName, curator, speciality FROM groups");
    while(rs.next()) {
      Group gr = new Group();
      gr.setGroupId(rs.getInt(1));
      gr.setNameGroup(rs.getString(2));
      gr.setCurator(rs.getString(3));
      gr.setSpeciality(rs.getString(4));

      groups.add(gr);
    }
    rs.close();
    stmt.close();
    
    return groups;
  }
    
  public Collection getAllStudents() throws SQLException
  {
    Collection students = new ArrayList();

    Statement stmt = con.createStatement();
    ResultSet rs = stmt.executeQuery(
        "SELECT student_id, firstName, patronymic, surName, "+
        "sex, dateOfBirth, group_id, educationYear FROM students ORDER BY surName, firstName, patronymic");
    while(rs.next()) {
      Student st = new Student(rs);
      students.add(st);
    }
    rs.close();
    stmt.close();

    return students;
  }

  public Collection getStudentsFromGroup(Group group, int year) throws SQLException 
  {
    Collection students = new ArrayList();

    PreparedStatement stmt = con.prepareStatement(
        "SELECT student_id, firstName, patronymic, surName, "+
        "sex, dateOfBirth, group_id, educationYear FROM students " +
        "WHERE group_id=? AND educationYear=? "+
        "ORDER BY surName, firstName, patronymic");
    stmt.setInt(1, group.getGroupId());
    stmt.setInt(2, year);
    ResultSet rs = stmt.executeQuery();
    while(rs.next()) {
      Student st = new Student(rs);
    
      students.add(st);
    }
    rs.close();
    stmt.close();
    
    return students;
  }

  public void moveStudentsToGroup(Group oldGroup, int oldYear, Group newGroup, int newYear) throws SQLException
  {
    PreparedStatement stmt = con.prepareStatement(
        "UPDATE students SET group_id=?, educationYear=? " +
        "WHERE group_id=? AND educationYear=?");
    stmt.setInt(1, newGroup.getGroupId());
    stmt.setInt(2, newYear);
    stmt.setInt(3, oldGroup.getGroupId());
    stmt.setInt(4, oldYear);
    stmt.execute();
  }
    
  public void removeStudentsFromGroup(Group group, int year) throws SQLException
  {
    PreparedStatement stmt = con.prepareStatement(
        "DELETE FROM students WHERE group_id=? AND educationYear=?");
    stmt.setInt(1, group.getGroupId());
    stmt.setInt(2, year);
    stmt.execute();
  }

  public void insertStudent(Student student) throws SQLException
  {
    PreparedStatement stmt = con.prepareStatement(
        "INSERT INTO students "+
        "(firstName, patronymic, surName, sex, dateOfBirth, group_id, educationYear) " +
        "VALUES (?, ?, ?, ?, ?, ?, ?)");
    stmt.setString(1, student.getFirstName());
    stmt.setString(2, student.getPatronymic());
    stmt.setString(3, student.getSurName());
    stmt.setString(4, new String(new char[] {student.getSex()} ));
    stmt.setDate(5, new Date(student.getDateOfBirth().getTime()));
    stmt.setInt(6, student.getGroupId());
    stmt.setInt(7, student.getEducationYear());

    stmt.execute();
  }
    
  public void updateStudent(Student student) throws SQLException
  {
    PreparedStatement stmt = con.prepareStatement(
        "UPDATE students SET "+
        "firstName=?, patronymic=?, surName=?, "+
        "sex=?, dateOfBirth=?, group_id=?, educationYear=? " +
        "WHERE student_id=?");
    stmt.setString(1, student.getFirstName());
    stmt.setString(2, student.getPatronymic());
    stmt.setString(3, student.getSurName());
    stmt.setString(4, new String(new char[] {student.getSex()} ));
    stmt.setDate(5, new Date(student.getDateOfBirth().getTime()));
    stmt.setInt(6, student.getGroupId());
    stmt.setInt(7, student.getEducationYear());
    stmt.setInt(8, student.getStudentId());
  
    stmt.execute();
  }
    
  public void deleteStudent(Student student) throws SQLException
  {
    PreparedStatement stmt = con.prepareStatement(
      "DELETE FROM students WHERE student_id=?");
    stmt.setInt(1, student.getStudentId());
    stmt.execute();
  }
}


GroupDialog.java
Код

package students.frame;

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;

import students.logic.Group;

public class GroupDialog extends JDialog implements ActionListener
{
  private static final int D_HEIGHT = 150;   // высота
  private final static int D_WIDTH = 200;   // ширина
  
  private JSpinner spYear;
  private JComboBox groupList;
  private JButton btnOk = new JButton("OK");
  private JButton btnCancel = new JButton("Cancel");
  
  private boolean result = false;
  
  public GroupDialog(int year, List groups)
  {
    // Установить заголовок
    setTitle("Перенос группы");
    
    // Создаем сложный layout для нашего окна
    GridBagLayout gbl = new GridBagLayout();
    setLayout(gbl);
    // Создаем переменную для установки правил размещения 
    GridBagConstraints c = new GridBagConstraints();
    // Сразу задаем отступ от границ для каждого элемента
    c.insets = new Insets(5,5,5,5);

    // Первый элемент - заголовок для поля выбора групп
    JLabel l = new JLabel("Новая группа:");
    // После него можно будет еще помещать компоненты
    c.gridwidth = GridBagConstraints.RELATIVE;
    // Не заполняем все пространство, отведенное компоненту
    c.fill = GridBagConstraints.NONE;
    // "Привязываем" компонент к правому краю
    c.anchor = GridBagConstraints.EAST;
    // Устанавливаем это правило для нашего компонета
    gbl.setConstraints(l, c);
    // Добавляем компонент
    getContentPane().add(l);

    // Второй элемент - список групп
    groupList = new JComboBox(new Vector(groups));
    // Элемент занимает всю оставшуюся ширину
    c.gridwidth = GridBagConstraints.REMAINDER;
    // Растягиваем компонент по всему пространству для него
    c.fill = GridBagConstraints.BOTH;
    // "Привязываем" его к левой части
    c.anchor = GridBagConstraints.WEST;
    // Устанавливаем это правило для нашего компонета
    gbl.setConstraints(groupList, c);
    // Добавляем компонент
    getContentPane().add(groupList);
    
    // Третий элемент - заголовок для поля выбора года
    l = new JLabel("Новый год:");
    // После него можно будет еще помещать компоненты
    c.gridwidth = GridBagConstraints.RELATIVE;
    // Не заполняем все пространство, отведенное компоненту
    c.fill = GridBagConstraints.NONE;
    // "Привязываем" компонент к правому краю
    c.anchor = GridBagConstraints.EAST;
    // Устанавливаем это правило для нашего компонета
    gbl.setConstraints(l, c);
    // Добавляем компонент
    getContentPane().add(l);
    
    // Сразу увеличиваем группу на один год - для перевода
    spYear = new JSpinner(new SpinnerNumberModel(year+1, 1900, 2100, 1));
    // Элемент занимает всю оставшуюся ширину
    c.gridwidth = GridBagConstraints.REMAINDER;
    // Растягиваем компонент по всему пространству для него
    c.fill = GridBagConstraints.BOTH;
    // "Привязываем" его к левой части
    c.anchor = GridBagConstraints.WEST;
    // Устанавливаем это правило для нашего компонета
    gbl.setConstraints(spYear, c);
    // Добавляем компонент
    getContentPane().add(spYear);
    
    c.gridwidth = GridBagConstraints.RELATIVE;
    c.fill = GridBagConstraints.BOTH;
    btnOk.setName("OK");
    // Добавляем листенер для кнопки
    btnOk.addActionListener(this);
    // Устанавливаем это правило для нашего компонета
    gbl.setConstraints(btnOk, c);
    // Добавляем компонент
    getContentPane().add(btnOk);

    btnCancel.setName("Cancel");
    // Добавляем листенер для кнопки
    btnCancel.addActionListener(this);
    // Устанавливаем это правило для нашего компонета
    gbl.setConstraints(btnCancel, c);
    // Добавляем компонент
    getContentPane().add(btnCancel);

    // Устанавливаем поведение формы при закрытии - не закрывать совсем.
    setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
    
    // Получаем размеры экрана
    Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
    // А теперь просто помещаем его по центру, вычисляя координаты на основе полученной информации
    setBounds(((int)d.getWidth() - GroupDialog.D_WIDTH) / 2, ((int)d.getHeight() - GroupDialog.D_HEIGHT) / 2, 
        GroupDialog.D_WIDTH, GroupDialog.D_HEIGHT);  
  }
  
  // Возврат года, который установлен на форме
  public int getYear()
  {
    return ((SpinnerNumberModel)spYear.getModel()).getNumber().intValue();
  }

  // Возврат группы, которая установлена на форме
  public Group getGroup()
  {
    if(groupList.getModel().getSize()>0) {
      return (Group)groupList.getSelectedItem(); 
    }
    return null;
  }
  
  // Получить результат, true - кнопка ОК, false - кнопка Cancel 
  public boolean getResult()
  {
    return result;
  }

  // Обработка нжатия кнопок
  public void actionPerformed(ActionEvent e)
  {
    JButton src = (JButton)e.getSource();
    if(src.getName().equals("OK")) {
      result = true;
    }
    if(src.getName().equals("Cancel")) {
      result = false;
    }
    setVisible(false);
  }
}


StudentDialog.java
Код

package students.frame;

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.Vector;

import javax.swing.AbstractButton;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JRadioButton;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerDateModel;
import javax.swing.SpinnerNumberModel;

import students.logic.Group;
import students.logic.ManagementSystem;
import students.logic.Student;

public class StudentDialog extends JDialog implements ActionListener
{
  private static final int D_HEIGHT = 200;   // высота окна
  private final static int D_WIDTH = 450;   // ширина окна
  
  private final static int L_X = 10;      // левая граница метки для поля
  private final static int L_W = 100;     // ширина метки для поля
  private final static int C_W = 150;     // ширина поля

  // Владелец нашего окна - вводим для вызова нужного нам метода
  private StudentsFrame owner;
  // Результат нажатия кнопок
  private boolean result = false;
  
  // Параметры студента 
  private int studentId = 0;
  private JTextField firstName = new JTextField();
  private JTextField surName = new JTextField();
  private JTextField patronymic = new JTextField();
  private JSpinner dateOfBirth = new JSpinner(new SpinnerDateModel(new Date(),null, null, Calendar.DAY_OF_MONTH));
  private ButtonGroup sex = new ButtonGroup();
  private JSpinner year = new JSpinner(new SpinnerNumberModel(2006, 1900, 2100, 1));
  private JComboBox groupList;

  // Второй параметр содержит знак - добавление студента или исправление
  public StudentDialog(List groups, boolean newStudent, StudentsFrame owner)
  {
    // После вставки студента без закрытия окна нам потребуется перегрузка списка
    // А для этого нам надо иметь доступ к этому методу в главной форме
    this.owner = owner;
    // Установить заголовок
    setTitle("Редактирование данных студента");
    getContentPane().setLayout(new FlowLayout());

    groupList = new JComboBox(new Vector(groups));
    
    JRadioButton m = new JRadioButton("Муж");
    JRadioButton w = new JRadioButton("Жен");
    // Сделаем имя такое же, как требуется в баще данных - М/Ж
    m.setActionCommand("М");
    w.setActionCommand("Ж");
    // Добавим радио-кнопки в группу
    sex.add(m);
    sex.add(w);
    
    // Не будем использовать layout совсем
    getContentPane().setLayout(null);
    
    // Разместим компоненты по абсолютным координатам
    // Фамилия
    JLabel l = new JLabel("Фамилия:", JLabel.RIGHT);
    l.setBounds(L_X, 10, L_W, 20);
    getContentPane().add(l);
    surName.setBounds(L_X+L_W+10, 10, C_W, 20);
    getContentPane().add(surName);
    // Имя
    l = new JLabel("Имя:", JLabel.RIGHT);
    l.setBounds(L_X, 30, L_W, 20);
    getContentPane().add(l);
    firstName.setBounds(L_X+L_W+10, 30, C_W, 20);
    getContentPane().add(firstName);
    // Отчество
    l = new JLabel("Отчество:", JLabel.RIGHT);
    l.setBounds(L_X, 50, L_W, 20);
    getContentPane().add(l);
    patronymic.setBounds(L_X+L_W+10, 50, C_W, 20);
    getContentPane().add(patronymic);
    // Пол
    l = new JLabel("Пол:", JLabel.RIGHT);
    l.setBounds(L_X, 70, L_W, 20);
    getContentPane().add(l);
    m.setBounds(L_X+L_W+10, 70, C_W/2, 20);
    getContentPane().add(m);
    // Сделаем по умолчанию женщину - из уважения
    w.setBounds(L_X+L_W+10+C_W/2, 70, C_W/2, 20);
    w.setSelected(true);
    getContentPane().add(w);
    // Дата рождения
    l = new JLabel("Дата рождения:", JLabel.RIGHT);
    l.setBounds(L_X, 90, L_W, 20);
    getContentPane().add(l);
    dateOfBirth.setBounds(L_X+L_W+10, 90, C_W, 20);
    getContentPane().add(dateOfBirth);
    // Группа
    l = new JLabel("Группа:", JLabel.RIGHT);
    l.setBounds(L_X, 115, L_W, 25);
    getContentPane().add(l);
    groupList.setBounds(L_X+L_W+10, 115, C_W, 25);
    getContentPane().add(groupList);
    // Год обучения
    l = new JLabel("Год обучения:", JLabel.RIGHT);
    l.setBounds(L_X, 145, L_W, 20);
    getContentPane().add(l);
    year.setBounds(L_X+L_W+10, 145, C_W, 20);
    getContentPane().add(year);
    
    JButton btnOk = new JButton("OK");
    btnOk.setName("OK");
    btnOk.addActionListener(this);
    btnOk.setBounds(L_X+L_W+C_W+10+50, 10, 100, 25);
    getContentPane().add(btnOk);
    
    JButton btnCancel = new JButton("Cancel");
    btnCancel.setName("Cancel");
    btnCancel.addActionListener(this);
    btnCancel.setBounds(L_X+L_W+C_W+10+50, 40, 100, 25);
    getContentPane().add(btnCancel);
    
    if(newStudent) {
      JButton btnNew = new JButton("New");
      btnNew.setName("New");
      btnNew.addActionListener(this);
      btnNew.setBounds(L_X+L_W+C_W+10+50, 70, 100, 25);
      getContentPane().add(btnNew);
    }
    
    // Устанавливаем поведение формы при закрытии - не закрывать совсем.
    setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
    
    // Получаем размеры экрана
    Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
    // А теперь просто помещаем его по центру, вычисляя координаты на основе полученной информации
    setBounds(((int)d.getWidth() - StudentDialog.D_WIDTH) / 2, ((int)d.getHeight() - StudentDialog.D_HEIGHT) / 2, 
        StudentDialog.D_WIDTH, StudentDialog.D_HEIGHT);  
  }

  // Установить поля соответственно переданным данным о студенте
  public void setStudent(Student st)
  {
    studentId = st.getStudentId();
    firstName.setText(st.getFirstName());
    surName.setText(st.getSurName());
    patronymic.setText(st.getPatronymic());
    dateOfBirth.getModel().setValue(st.getDateOfBirth());
    for(Enumeration e=sex.getElements(); e.hasMoreElements(); ) {
      AbstractButton ab = (AbstractButton)e.nextElement();
      ab.setSelected(ab.getActionCommand().equals(new String(""+st.getSex())));
    }
    year.getModel().setValue(new Integer(st.getEducationYear()));
    for(int i=0; i<groupList.getModel().getSize(); i++) {
      Group g = (Group)groupList.getModel().getElementAt(i);
      if(g.getGroupId()==st.getGroupId()) {
        groupList.setSelectedIndex(i);
        break;
      }
    }
  }

  // Вернуть данные в виде нового студента с соотвтествующими полями
  public Student getStudent()
  {
    Student st = new Student();
    st.setStudentId(studentId);
    st.setFirstName(firstName.getText());
    st.setSurName(surName.getText());
    st.setPatronymic(patronymic.getText());
    Date d = ((SpinnerDateModel)dateOfBirth.getModel()).getDate();
    st.setDateOfBirth(d);
    for(Enumeration e=sex.getElements(); e.hasMoreElements(); ) {
      AbstractButton ab = (AbstractButton)e.nextElement();
      if(ab.isSelected()) {
        st.setSex(ab.getActionCommand().charAt(0));
      }
    }
    int y = ((SpinnerNumberModel)year.getModel()).getNumber().intValue();
    st.setEducationYear(y);
    st.setGroupId(((Group)groupList.getSelectedItem()).getGroupId());
    return st;
  }
  
  // Получить результат, true - кнопка ОК, false - кнопка Cancel 
  public boolean getResult()
  {
    return result;
  }
  
  public void actionPerformed(ActionEvent e)
  {
    JButton src = (JButton)e.getSource();
    // Добавляем студента, но не закрываем окно
    // Здесь мы не будем вызывать в отдельном потоке сохранение. 
    // Оно не занимаем много времени и лишние действия здесь не оправданы
    if(src.getName().equals("New")) {
      result = true;
      try {
        ManagementSystem.getInstance().insertStudent(getStudent());
        owner.reloadStudents();
        firstName.setText("");
        surName.setText("");
        patronymic.setText("");
      } catch (SQLException sql_e) {
        JOptionPane.showMessageDialog(this, sql_e.getMessage());
      }
      return;
    }
    if(src.getName().equals("OK")) {
      result = true;
    }
    if(src.getName().equals("Cancel")) {
      result = false;
    }
    setVisible(false);
  }

}


StudentTableModel.java
Код

package students.frame;

import java.text.DateFormat;
import java.util.Vector;

import javax.swing.table.AbstractTableModel;

import students.logic.Student;

public class StudentTableModel extends AbstractTableModel
{
  // Сделаем хранилище для нашего списка студентов
  private Vector students;

  // Модель при создании получает список студентов
  public StudentTableModel(Vector students)
  {
    this.students = students;
  }

  // Количество строк равно числу записей
  public int getRowCount()
  {
    if (students != null) {
      return students.size();
    }
    return 0;
  }

  // Количество столбцов - 4. Фамилия, Имя, Отчество, Дата рождения
  public int getColumnCount()
  {
    return 4;
  }

  // Вернем наименование колонки
  public String getColumnName(int column)
  {
    String[] colNames = { "Фамилия", "Имя", "Отчество", "Дата" };
    return colNames[column];
  }

  // Возвращаем данные для определенной строки и столбца
  public Object getValueAt(int rowIndex, int columnIndex)
  {
    if (students != null) {
      // Получаем из вектора студента
      Student st = (Student) students.get(rowIndex);
      // В зависимости от колонки возвращаем имя, фамилия и т.д.
      switch (columnIndex) {
      case 0:
        return st.getSurName();
      case 1:
        return st.getFirstName();
      case 2:
        return st.getPatronymic();
      case 3:
        return DateFormat.getDateInstance(DateFormat.SHORT).format(
            st.getDateOfBirth());
      }
    }
    return null;
  }

  // Добавим метод, который возвращает студента по номеру строки
  // Это нам пригодится чуть позже
  public Student getStudent(int rowIndex) 
  {
    if(students!=null) {
      if(rowIndex<students.size() && rowIndex>=0) {
        return (Student)students.get(rowIndex);
      }
    }
    return null;
  }
}


StudentsFrame.java
Код

package students.frame;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTable;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.border.BevelBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import students.logic.Group;
import students.logic.ManagementSystem;
import students.logic.Student;

public class StudentsFrame extends JFrame implements ActionListener,
    ListSelectionListener, ChangeListener
{
  // Введем сразу имена для кнопок - потом будем их использовать в обработчиках
  private static final String MOVE_GR = "moveGroup";
  private static final String CLEAR_GR = "clearGroup";
  private static final String INSERT_ST = "insertStudent";
  private static final String UPDATE_ST = "updateStudent";
  private static final String DELETE_ST = "deleteStudent";
  private static final String ALL_STUDENTS = "allStudent";

  ManagementSystem ms = ManagementSystem.getInstance();
  private JList grpList;
  private JTable stdList;
  private JSpinner spYear;

  public StudentsFrame()
  {
    // Устанавливаем layout для всей клиентской части формы
    getContentPane().setLayout(new BorderLayout());

    // Создаем строку меню
    JMenuBar menuBar = new JMenuBar();
    // Создаем выпадающее меню
    JMenu menu = new JMenu("Отчеты");
    // Создаем пункт в выпадающем меню
    JMenuItem menuItem = new JMenuItem("Все студенты");
    menuItem.setName(ALL_STUDENTS);
    // Добавляем листенер
    menuItem.addActionListener(this);
    // Вставляем пункт меню в выпадающее меню
    menu.add(menuItem);
    // Вставляем выпадающее меню в строку меню
    menuBar.add(menu);
    // Устанавливаем меню для формы
    setJMenuBar(menuBar);

    // Создаем верхнюю панель, где будет поле для ввода года
    JPanel top = new JPanel();
    // Устанавливаем для нее layout
    top.setLayout(new FlowLayout(FlowLayout.LEFT));

    // Вставляем пояснительную надпись
    top.add(new JLabel("Год обучения:"));
    // Делаем спин-поле
    // 1. Задаем модель поведения - только цифры
    // 2. Вставляем в панель
    SpinnerModel sm = new SpinnerNumberModel(2006, 1900, 2100, 1);
    spYear = new JSpinner(sm);
    // Добавляем листенер
    spYear.addChangeListener(this);
    top.add(spYear);

    // Создаем нижнюю панель и задаем ей layout
    JPanel bot = new JPanel();
    bot.setLayout(new BorderLayout());

    // Создаем левую панель для вывода списка групп
    // Она у нас
    GroupPanel left = new GroupPanel();
    // Задаем layout и задаем "бордюр" вокруг панели
    left.setLayout(new BorderLayout());
    left.setBorder(new BevelBorder(BevelBorder.LOWERED));

    // Нам необходимо обработать ошибку при обращении к базе данных
    Vector gr = null;
    try {
      // Получаем список групп
      gr = new Vector(ms.getGroups());
    } catch (SQLException e) {
      e.printStackTrace();
    }
    // Создаем надпись
    left.add(new JLabel("Группы:"), BorderLayout.NORTH);
    // Создаем визуальный список и вставляем его в скроллируемую
    // панель, которую в свою очередь уже кладем на панель left
    grpList = new JList(gr);
    // Добавляем листенер
    grpList.addListSelectionListener(this);
    left.add(new JScrollPane(grpList), BorderLayout.CENTER);
    // Создаем кнопки для групп
    JButton btnMvGr = new JButton("Переместить");
    btnMvGr.setName(MOVE_GR);
    JButton btnClGr = new JButton("Очистить");
    btnClGr.setName(CLEAR_GR);
    // Добавляем листенер
    btnMvGr.addActionListener(this);
    btnClGr.addActionListener(this);
    // Создаем панель, на которую положим наши кнопки и кладем ее вниз
    JPanel pnlBtnGr = new JPanel();
    pnlBtnGr.setLayout(new GridLayout(1, 2));
    pnlBtnGr.add(btnMvGr);
    pnlBtnGr.add(btnClGr);
    left.add(pnlBtnGr, BorderLayout.SOUTH);

    // Создаем правую панель для вывода списка студентов
    JPanel right = new JPanel();
    // Задаем layout и задаем "бордюр" вокруг панели
    right.setLayout(new BorderLayout());
    right.setBorder(new BevelBorder(BevelBorder.LOWERED));

    // Создаем надпись
    right.add(new JLabel("Студенты:"), BorderLayout.NORTH);
    // Создаем таблицу и вставляем ее в скроллируемую
    // панель, которую в свою очередь уже кладем на панель right
    // Наша таблица пока ничего не умеет - просто положим ее как заготовку
    // Сделаем в ней 4 колонки - Фамилия, Имя, Отчество, Дата рождения
    stdList = new JTable(1, 4);
    right.add(new JScrollPane(stdList), BorderLayout.CENTER);
    // Создаем кнопки для студентов
    JButton btnAddSt = new JButton("Добавить");
    btnAddSt.setName(INSERT_ST);
    btnAddSt.addActionListener(this);
    JButton btnUpdSt = new JButton("Исправить");
    btnUpdSt.setName(UPDATE_ST);
    btnUpdSt.addActionListener(this);
    JButton btnDelSt = new JButton("Удалить");
    btnDelSt.setName(DELETE_ST);
    btnDelSt.addActionListener(this);
    // Создаем панель, на которую положим наши кнопки и кладем ее вниз
    JPanel pnlBtnSt = new JPanel();
    pnlBtnSt.setLayout(new GridLayout(1, 3));
    pnlBtnSt.add(btnAddSt);
    pnlBtnSt.add(btnUpdSt);
    pnlBtnSt.add(btnDelSt);
    right.add(pnlBtnSt, BorderLayout.SOUTH);

    // Вставляем панели со списками групп и студентов в нижнюю панель
    bot.add(left, BorderLayout.WEST);
    bot.add(right, BorderLayout.CENTER);

    // Вставляем верхнюю и нижнюю панели в форму
    getContentPane().add(top, BorderLayout.NORTH);
    getContentPane().add(bot, BorderLayout.CENTER);

    // Сразу выделяем первую группу
    grpList.setSelectedIndex(0);

    // Задаем границы формы
    setBounds(100, 100, 700, 500);
  }

  public static void main(String args[])
  {
    StudentsFrame sf = new StudentsFrame();
    sf.setDefaultCloseOperation(EXIT_ON_CLOSE);
    sf.setVisible(true);
  }

  // Метод для обеспечения интерфейса ActionListener
  public void actionPerformed(ActionEvent e)
  {
    if (e.getSource() instanceof Component) {
      Component c = (Component) e.getSource();
      if (c.getName().equals(MOVE_GR)) {
        moveGroup();
      }
      if (c.getName().equals(CLEAR_GR)) {
        clearGroup();
      }
      if (c.getName().equals(ALL_STUDENTS)) {
        showAllStudents();
      }
      if (c.getName().equals(INSERT_ST)) {
        insertStudent();
      }
      if (c.getName().equals(UPDATE_ST)) {
        updateStudent();
      }
      if (c.getName().equals(DELETE_ST)) {
        deleteStudent();
      }
    }
  }

  // Метод для обеспечения интерфейса ListSelectionListener
  public void valueChanged(ListSelectionEvent e)
  {
    if (!e.getValueIsAdjusting()) {
      reloadStudents();
    }
  }

  // Метод для обеспечения интерфейса ChangeListener
  public void stateChanged(ChangeEvent e)
  {
    reloadStudents();
  }

  // метод для обновления списка студентов для определенной группы
  public void reloadStudents()
  {
    // Создаем анонимный класс для потока
    Thread t = new Thread() {
      // Переопределяем в нем метод run
      public void run()
      {
        if (stdList != null) {
          // Получаем выделенную группу
          Group g = (Group) grpList.getSelectedValue();
          // Получаем число из спинера
          int y = ((SpinnerNumberModel) spYear.getModel()).getNumber()
              .intValue();
          try {
            // Получаем список студентов
            Collection s = ms.getStudentsFromGroup(g, y);
            // И устанавливаем модель для таблицы с новыми данными
            stdList.setModel(new StudentTableModel(new Vector(s)));
          } catch (SQLException e) {
            JOptionPane.showMessageDialog(StudentsFrame.this, e.getMessage());
          }
        }
      }
      // Окончание нашего метода run
    };
    // Окончание определения анонимного класса
    // И теперь мы запускаем наш поток
    t.start();
  }

  // метод для переноса группы
  private void moveGroup()
  {
    Thread t = new Thread() {
      public void run()
      {
        // Если группа не выделена - выходим. Хотя это крайне маловероятно
        if (grpList.getSelectedValue() == null) {
          return;
        }
        try {
          // Получаем выделенную группу
          Group g = (Group) grpList.getSelectedValue();
          // Получаем число из спинера
          int y = ((SpinnerNumberModel) spYear.getModel()).getNumber().intValue();
          // Создаем наш диалог
          GroupDialog gd = new GroupDialog(y, ms.getGroups());
          // Задаем ему режим модальности - нельзя ничего кроме него выделить
          gd.setModal(true);
          // Показываем диалог
          gd.setVisible(true);
          // Если нажали кнопку OK - перемещаем в новую группу с новым годом
          // и перегружаем список студентов
          if (gd.getResult()) {
            ms.moveStudentsToGroup(g, y, gd.getGroup(), gd.getYear());
            reloadStudents();
          }
        } catch (SQLException e) {
          JOptionPane.showMessageDialog(StudentsFrame.this, e.getMessage());
        }
      }
    };
    t.start();
  }

  // метод для очистки группы
  private void clearGroup()
  {
    Thread t = new Thread() {
      public void run()
      {
        // Проверяем - выделена ли группа
        if (grpList.getSelectedValue() != null) {
          if (JOptionPane.showConfirmDialog(StudentsFrame.this,
              "Вы хотите удалить студентов из группы?", "Удаление студентов",
              JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
            // Получаем выделенную группу
            Group g = (Group) grpList.getSelectedValue();
            // Получаем число из спинера
            int y = ((SpinnerNumberModel) spYear.getModel()).getNumber().intValue();
            try {
              // Удалили студентов из группы
              ms.removeStudentsFromGroup(g, y);
              // перегрузили список студентов
              reloadStudents();
            } catch (SQLException e) {
              JOptionPane.showMessageDialog(StudentsFrame.this, e.getMessage());
            }
          }
        }
      }
    };
    t.start();
  }

  // метод для добавления студента
  private void insertStudent()
  {
    Thread t = new Thread() {
      public void run()
      {
        try {
          // Добавляем нового студента - поэтому true
          // Также заметим, что необходимо указать не просто this, а StudentsFrame.this
          // Иначе класс не будет воспринят - он же другой - анонимный
          StudentDialog sd = new StudentDialog(ms.getGroups(), true, StudentsFrame.this);
          sd.setModal(true);
          sd.setVisible(true);
          if (sd.getResult()) {
            Student s = sd.getStudent();
            ms.insertStudent(s);
            reloadStudents();
          }
        } catch (SQLException e) {
          JOptionPane.showMessageDialog(StudentsFrame.this, e.getMessage());
        }
      }
    };
    t.start();
  }

  // метод для редактирования студента
  private void updateStudent()
  {
    Thread t = new Thread() {
      public void run()
      {
        if (stdList != null) {
          StudentTableModel stm = (StudentTableModel) stdList.getModel();
          // Проверяем - выделен ли хоть какой-нибудь студент
          if (stdList.getSelectedRow() >= 0) {
            // Вот где нам пригодился метод getStudent(int rowIndex)
            Student s = stm.getStudent(stdList.getSelectedRow());
            try {
              // Исправляем данные на студента - поэтому false
              // Также заметим, что необходимо указать не просто this, а StudentsFrame.this
              // Иначе класс не будет воспринят - он же другой - анонимный
              StudentDialog sd = new StudentDialog(ms.getGroups(), false, StudentsFrame.this);
              sd.setStudent(s);
              sd.setModal(true);
              sd.setVisible(true);
              if (sd.getResult()) {
                Student us = sd.getStudent();
                ms.updateStudent(us);
                reloadStudents();
              }
            } catch (SQLException e) {
              JOptionPane.showMessageDialog(StudentsFrame.this, e.getMessage());
            }
          }
          // Если студент не выделен - сообщаем пользователю, что это необходимо
          else {
            JOptionPane.showMessageDialog(StudentsFrame.this,
                "Необходимо выделить студента в списке");
          }
        }
      }
    };
    t.start();
  }

  // метод для удаления студента
  private void deleteStudent()
  {
    Thread t = new Thread() {
      public void run()
      {
        if (stdList != null) {
          StudentTableModel stm = (StudentTableModel) stdList.getModel();
          // Проверяем - выделен ли хоть какой-нибудь студент
          if (stdList.getSelectedRow() >= 0) {
            if (JOptionPane.showConfirmDialog(StudentsFrame.this,
                "Вы хотите удалить студента?", "Удаление студента",
                JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
              // Вот где нам пригодился метод getStudent(int rowIndex)
              Student s = stm.getStudent(stdList.getSelectedRow());
              try {
                ms.deleteStudent(s);
                reloadStudents();
              } catch (SQLException e) {
                JOptionPane.showMessageDialog(StudentsFrame.this, e
                    .getMessage());
              }
            }
          }
          // Если студент не выделен - сообщаем пользователю, что это необходимо
          else {
            JOptionPane.showMessageDialog(StudentsFrame.this,
                "Необходимо выделить студента в списке");
          }
        }
      }
    };
    t.start();
  }

  // метод для показа всех студентов
  private void showAllStudents()
  {
    JOptionPane.showMessageDialog(this, "showAllStudents");
  }
}

// Наш внутренний класс - переопределенная панель.
class GroupPanel extends JPanel
{

  public Dimension getPreferredSize()
  {
    return new Dimension(250, 0);
  }
}


Итак, мы в общих чертах прошли по возможностям JAVA в части работы с коллекциями, базами данных и пользовательским интерфейсом. Теперь нас ждет путешествие в мир WEB - мы посмотрим, как можно создавать Интернет-приложения, как пользоваться сервлетами, java-server pages (JSP) и другими технологиями JAVA для мира Интернет. Итак, встречайте Часть 7 - Первые шаги в Интернет
Автор: AntonSaburov






Просмотров: 5168

 

 

Новые статьи:


Популярные:
  1. Как сделать цикличным проигрывание MIDI-файла?
  2. Создание AVI файла из рисунков
  3. Как устройство "отключить в данной конфигурации"?
  4. Kто в данный момент присоединен через Сеть?
  5. Как узнать количество доступной памяти?
  6. Как реализовать в RichEdit разноцветный текст?
  7. Как скрыть свое приложение от ProcessViewer
  8. Как программно нажать/скрыть/показ кнопку "Start"?
  9. Модуль работы с ресурсами в PE файлах
10. Функции вызова диалоговых окон выбора
11. Проверка граматики средствами Word'а из Delphi.
12. Модуль для упрощенного вызова сообщений
13. Функции для записи и чтение своих данных в, ЕХЕ- файле
14. Рекурсивный просмотр директорий
15. Network Traffic Monitor
16. Разные модули
17. Универсальная функция для обращения к любым экспортируем функциям DLL
18. Библиотека от VladS
19. Протектор для UPX'а
20. Еще об ICQ, сообщения по контакт листу?
21. Использование открытых интерфейсов
22. Теория и практика использования RTTI
23. Работа с TApplication
24. Примеры использования Drag and Drop для различных визуальных компонентов
25. Что такое порт? Правила для работы с портами
26. Симфония на клавиатуре
27. Загрузка DLL
28. Исправление автоинкремента
29. Взаимодействие с чужими окнами
30. Проверить дубляжи в столбце


 

 

 
 
На главную