Книга 1 - Начальные сведения
Книга 2 - Более профессиональный подход |
Студенческий отдел кадров Первый вариант пользовательского интерфейса
Если бы Вы попробовали собрать наш первый поект и запустить его под ОС Windows и при этом
закомментировать строки перенаправления вывода данных, то скорее всего Вас постигло большое
разочарование - на экране были сплошные закорючки и ничего не было понятно. Вероятнее всего
Вы уже догадались, что проблема кроется в том, что текст мы набирали
в кодировке Windows, а из командной строки весь вывод шел в кодировке MS-DOS. Предварительно мы опишем то, что хочется увидеть на экране.
Для показа групп и студентов нам потребуется список. Элементами для команд на редактирование пока будут кнопки. Для ввода информации - диалоговые окна. Ну и конечно же нам потребуется самое главное окно, в котором мы будем выполнять все наши действия. Самое главное окно обычно наследуется от класса JFrame. Для того, чтобы создать очень простое оконное приложение надо очень мало строк. import javax.swing.JFrame; import javax.swing.SwingUtilities; public class MainFrame extends JFrame { public MainFrame() { setBounds(100, 100, 300, 200); } public static void main(String[] args) { // Запуск формы лучше производить в специальном треде // event-dispatching thread - EDT SwingUtilities.invokeLater(new Runnable() { public void run() { MainFrame mf = new MainFrame(); mf.setDefaultCloseOperation(EXIT_ON_CLOSE); mf.setVisible(true); } }); } }
Небольшой комментарий: В самом конструкторе нашего приложения
(MainFrame) мы вызываем только один метод, который уже существует в
JFrame - setBounds. Этот метод служит
для установки размеров нашего окна. Для сборки и запуска нашего простого примера используются команды
javac MainFrame.java Конечно же мы рассмотрели очень просто приложение - нам необходимо будет его усложнить. Для этого мы рассмотрим несколько основных понятий, которые необходимо усвоить для более ясного представления, как работать с этой весьма разнообразной библиотекой.
Контейнеры
Слушатели - Listeners
Модели Давайте для начала создадим достаточно простое приложение, которое не умеет многое. Я здесь преследую две цели:
Прежде чем смотреть код - немного слов о менеджере разметки - layout manager.
Во-первых, достаточно подробно он рассмотрен здесь:
Форма будет разделена на две части - верхнюю и нижнюю. На верхней части будет компонент для
ввода года. Мы его сделаем в виде числового слайдера (спинера). В общем элемент со стрелками
вверх-вниз. Нижняя часть будет несколько сложнее - она поделится на две части. На левой будет
список групп, а на правой список студентов. Пока у нас будет полный список. Когда мы будем
более подробно рассматривать SWING мы усложним наше приложение.
Student.java package students.logic; import java.text.Collator; import java.text.DateFormat; import java.util.Date; import java.util.Locale; 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; // get/set для ДАТА РОЖДЕНИЯ public Date getDateOfBirth() { return dateOfBirth; } public void setDateOfBirth(Date dateOfBirth) { this.dateOfBirth = dateOfBirth; } // get/set для ГОД ОБУЧЕНИЯ public int getEducationYear() { return educationYear; } public void setEducationYear(int educationYear) { this.educationYear = educationYear; } // get/set для ИД ГРУППЫ public int getGroupId() { return groupId; } public void setGroupId(int groupId) { this.groupId = groupId; } // get/set для ИД СТУДЕНТА public int getStudentId() { return studentId; } public void setStudentId(int studentId) { this.studentId = studentId; } // get/set для ИМЯ public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } // get/set для ОТЧЕСТВО public String getPatronymic() { return patronymic; } public void setPatronymic(String patronymic) { this.patronymic = patronymic; } // get/set для ФАМИЛИЯ public String getSurName() { return surName; } public void setSurName(String surName) { this.surName = surName; } // get/set для ПОЛ public char getSex() { return sex; } public void setSex(char sex) { this.sex = sex; } // DateFormat - класс для преобразования даты // в строку в определеннном формате. // Подробнее смотрите документацию по этому методу public String toString() { return surName + " " + firstName + " " + patronymic + ", " + DateFormat.getDateInstance(DateFormat.SHORT).format(dateOfBirth) + ", Группа ИД=" + groupId + " Год:" + educationYear; } public int compareTo(Object obj) { Collator c = Collator.getInstance(new Locale("ru")); c.setStrength(Collator.PRIMARY); return c.compare(this.toString(), obj.toString()); } }
Group.java package students.logic; public class Group { // поле ИД ГРУППЫ private int groupId; // поле ИМЯ ГРУППЫ private String nameGroup; // поле КУРАТОР private String curator; // поле СПЕЦИАЛЬНОСТЬ private String speciality; // get/set для КУРАТОР public String getCurator() { return curator; } public void setCurator(String curator) { this.curator = curator; } // get/set для ИД ГРУППЫ public int getGroupId() { return groupId; } public void setGroupId(int groupId) { this.groupId = groupId; } // get/set для ИМЯ ГРУППЫ public String getNameGroup() { return nameGroup; } public void setNameGroup(String nameGroup) { this.nameGroup = nameGroup; } // get/set для СПЕЦИАЛЬНОСТЬ 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.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.List; import java.util.TreeSet; public class ManagementSystem { private List<Group> groups; private Collection<Student> students; // Для шаблона Singletone статическая переменная private static ManagementSystem instance; // закрытый конструктор private ManagementSystem() { loadGroups(); loadStudents(); } // метод getInstance - проверяtт, инициализирована ли статическая // переменная (в случае надобности делает это) и возвращает ее public static synchronized ManagementSystem getInstance() { if (instance == null) { instance = new ManagementSystem(); } return instance; } // Метод создает две группы и помещает их в коллекцию для групп public void loadGroups() { // Проверяем - может быть наш список еще не создан вообще if (groups == null) { groups = new ArrayList<Group>(); } else { groups.clear(); } Group g = null; g = new Group(); g.setGroupId(1); g.setNameGroup("Первая"); g.setCurator("Доктор Борменталь"); g.setSpeciality("Создание собачек из человеков"); groups.add(g); g = new Group(); g.setGroupId(2); g.setNameGroup("Вторая"); g.setCurator("Профессор Преображенский"); g.setSpeciality("Создание человеков из собачек"); groups.add(g); } // Метод создает несколько студентов и помещает их в коллекцию public void loadStudents() { if (students == null) { // Мы используем коллекцию, которая автоматически сортирует свои элементы students = new TreeSet<Student>(); } else { students.clear(); } Student s = null; Calendar c = Calendar.getInstance(); // Вторая группа s = new Student(); s.setStudentId(1); s.setFirstName("Иван"); s.setPatronymic("Сергеевич"); s.setSurName("Степанов"); s.setSex('М'); c.set(1990, 3, 20); s.setDateOfBirth(c.getTime()); s.setGroupId(2); s.setEducationYear(2006); students.add(s); s = new Student(); s.setStudentId(2); s.setFirstName("Наталья"); s.setPatronymic("Андреевна"); s.setSurName("Чичикова"); s.setSex('Ж'); c.set(1990, 6, 10); s.setDateOfBirth(c.getTime()); s.setGroupId(2); s.setEducationYear(2006); students.add(s); // Первая группа s = new Student(); s.setStudentId(3); s.setFirstName("Петр"); s.setPatronymic("Викторович"); s.setSurName("Сушкин"); s.setSex('М'); c.set(1991, 3, 12); s.setDateOfBirth(c.getTime()); s.setEducationYear(2006); s.setGroupId(1); students.add(s); s = new Student(); s.setStudentId(4); s.setFirstName("Вероника"); s.setPatronymic("Сергеевна"); s.setSurName("Ковалева"); s.setSex('Ж'); c.set(1991, 7, 19); s.setDateOfBirth(c.getTime()); s.setEducationYear(2006); s.setGroupId(1); students.add(s); } // Получить список групп public List<Group> getGroups() { return groups; } // Получить список всех студентов public Collection<Student> getAllStudents() { return students; } // Получить список студентов для определенной группы public Collection<Student> getStudentsFromGroup(Group group, int year) { Collection<Student> l = new TreeSet<Student>(); for (Student si : students) { if (si.getGroupId() == group.getGroupId() && si.getEducationYear() == year) { l.add(si); } } return l; } // Перевести студентов из одной группы с одним годом обучения в другую группу с другим годом обучения public void moveStudentsToGroup(Group oldGroup, int oldYear, Group newGroup, int newYear) { for (Student si : students) { if (si.getGroupId() == oldGroup.getGroupId() && si.getEducationYear() == oldYear) { si.setGroupId(newGroup.getGroupId()); si.setEducationYear(newYear); } } } // Удалить всех студентов из определенной группы public void removeStudentsFromGroup(Group group, int year) { // Мы создадим новый список студентов БЕЗ тех, кого мы хотим удалить. // Возможно не самый интересный вариант. Можно было бы продемонстрировать // более элегантный метод, но он требует погрузиться в коллекции более глубоко // Здесь мы не ставим себе такую цель Collection<Student> tmp = new TreeSet<Student>(); for (Student si : students) { if (si.getGroupId() != group.getGroupId() || si.getEducationYear() != year) { tmp.add(si); } } students = tmp; } // Добавить студента public void insertStudent(Student student) { // Просто добавляем объект в коллекцию students.add(student); } // Обновить данные о студенте public void updateStudent(Student student) { // Надо найти нужного студента (по его ИД) и заменить поля Student updStudent = null; for (Student si : students) { if (si.getStudentId() == student.getStudentId()) { // Вот этот студент - запоминаем его и прекращаем цикл updStudent = si; break; } } updStudent.setFirstName(student.getFirstName()); updStudent.setPatronymic(student.getPatronymic()); updStudent.setSurName(student.getSurName()); updStudent.setSex(student.getSex()); updStudent.setDateOfBirth(student.getDateOfBirth()); updStudent.setGroupId(student.getGroupId()); updStudent.setEducationYear(student.getEducationYear()); } // Удалить студента public void deleteStudent(Student student) { // Надо найти нужного студента (по его ИД) и удалить Student delStudent = null; for (Student si : students) { if (si.getStudentId() == student.getStudentId()) { // Вот этот студент - запоминаем его и прекращаем цикл delStudent = si; break; } } students.remove(delStudent); } }
И наконец класс для нашей формы -
StudentsFrame.java package students.frame; import java.util.Vector; import java.awt.FlowLayout; import java.awt.BorderLayout; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSpinner; import javax.swing.SpinnerModel; import javax.swing.SpinnerNumberModel; import javax.swing.SwingUtilities; import javax.swing.border.BevelBorder; import students.logic.Group; import students.logic.ManagementSystem; import students.logic.Student; public class StudentsFrame extends JFrame { ManagementSystem ms = ManagementSystem.getInstance(); private JList grpList; private JList stdList; private JSpinner spYear; public StudentsFrame() { // Устанавливаем layout для всей клиентской части формы getContentPane().setLayout(new BorderLayout()); // Создаем верхнюю панел, где будет поле для ввода года 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); top.add(spYear); // Создаем нижнюю панель и задаем ей layout JPanel bot = new JPanel(); bot.setLayout(new BorderLayout()); // Создаем левую панель для вывода списка групп JPanel left = new JPanel(); // Задаем layout и задаем "бордюр" вокруг панели left.setLayout(new BorderLayout()); left.setBorder(new BevelBorder(BevelBorder.RAISED)); // Получаем список групп Vector<Group> gr = new Vector<Group>(ms.getGroups()); // Создаем надпись left.add(new JLabel("Группы:"), BorderLayout.NORTH); // Создаем визуальный список и вставляем его в скроллируемую // панель, которую в свою очередь уже кладем на панель left grpList = new JList(gr); left.add(new JScrollPane(grpList), BorderLayout.CENTER); // Создаем правую панель для вывода списка студентов JPanel right = new JPanel(); // Задаем layout и задаем "бордюр" вокруг панели right.setLayout(new BorderLayout()); right.setBorder(new BevelBorder(BevelBorder.RAISED)); // Получаем список студентов Vector<Student> st = new Vector<Student>(ms.getAllStudents()); // Создаем надпись right.add(new JLabel("Студенты:"), BorderLayout.NORTH); // Создаем визуальный список и вставляем его в скроллируемую // панель, которую в свою очередь уже кладем на панель right stdList = new JList(st); right.add(new JScrollPane(stdList), BorderLayout.CENTER); // Вставляем панели со списками групп и студентов в нижнюю панель bot.add(left, BorderLayout.WEST); bot.add(right, BorderLayout.CENTER); // Вставляем верхнюю и нижнюю панели в форму getContentPane().add(top, BorderLayout.NORTH); getContentPane().add(bot, BorderLayout.CENTER); // Задаем границы формы setBounds(100, 100, 600, 400); } public static void main(String args[]) { // Запуск формы лучше производить в специальном треде // event-dispatching thread - EDT SwingUtilities.invokeLater(new Runnable() { public void run() { StudentsFrame sf = new StudentsFrame(); sf.setDefaultCloseOperation(EXIT_ON_CLOSE); sf.setVisible(true); } }); } }
ВНИМАНИЕ!!!
/student
- /frame
- StudentsFrame.java
- /logic
- Student.java
- Group.java
- ManagementSystem.java
Для сборки нам потребуется команда
javac students/frame/*.java students/logic/*.java Для сборки примера из архива javac -encoding UTF-8 students/frame/*.java students/logic/*.java Для запуска наберите следующую команду: java -cp . students.frame.StudentsFrame
Как видите наше приложение уже что-то может. Если Вы попробуете уменьшить окно, то в какой-то момент
увидите, что появяться линейки прокрутки. Конечно, наши данные еще далеки от совершенства и каждый раз
будут исчезать из памяти. Для того, чтобы они не исчезали мы используем
Часть 3 - Базы данных Архив с исходными кодами: Исходный код |