Книга 1 - Начальные сведения
Книга 2 - Более профессиональный подход |
Студенческий отдел кадров Список - model и listeners. Пример попрощеДавайте рассмотрим постепенно все необходимые нам части пользовательского интерфейса. И начнем мы со списка групп. Здесь нас будет интересовать два момента:
Наше самое простое приложение будет выглядеть вот так: import java.util.*; import javax.swing.*; public class Test extends JFrame { private JList list; public Test() { // Для инициализации списка нам потребуется вектор - посмотрите коллекции Vector v = new Vector(); v.add("1"); v.add("2"); v.add("3"); v.add("4"); v.add("5"); list = new JList(v); // Добавляем список на панель формы getContentPane().add(new JScrollPane(list)); // Устанавливаем границы setBounds(100, 100, 200, 200); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { Test t = new Test(); t.setDefaultCloseOperation(t.EXIT_ON_CLOSE); t.setVisible(true); } }); } }
В общем ничего сложного пока нет. Давайте теперь добавим в наш список возможность реагировать на
события - а именно на перемещение указателя. Теперь мы вплотную подошли в слушателям
(listeners). По сути они и являются теми самыми контроллерами в
паттерне MVC (Model-View-Controller).
Если Вы внимательно читали первую часть посвященную SWING, то помните, что механизм листенеров
(автор приносит свои извинения за русский вариант английского слова, но в программистской среде
понятие "слушатель" встречается крайне редко) основан на простой идее - объект, который принимает
какие-либо события может содержать список объектов, которые "подписались" на "прослушку" событий.
Т.е. для примера - кнопка при своем нажатии проверяет список листенеров и каждому посылает сообщение,
что ее нажали. Предварительно каждый, кто хочет знать о нажатии добавляет себя в список листенеров
для кнопки. Чтобы принять сообщение от кнопки листенер должен реализовать интерфейс. Давайте посмотрим
это на примере. import java.util.*; import javax.swing.*; import javax.swing.event.*; // Обратите внимание, что теперь наша форма реализует интерфейс public class Test extends JFrame implements ListSelectionListener { private JList list; public Test() { // Для инициализации списка нам потребуется вектор - посмотрите коллекции Vector v = new Vector(); v.add("1"); v.add("2"); v.add("3"); v.add("4"); v.add("5"); list = new JList(v); // Вот здесь выставляем режим выделения одного пункта list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); // Список будет посылать сообщения форме list.addListSelectionListener(this); // Добавляем список на панель формы getContentPane().add(new JScrollPane(list)); // Устанавливаем границы setBounds(100, 100, 200, 200); } // Единственный метод, который реализует интерфейс ListSelectionListener public void valueChanged(ListSelectionEvent e) { System.out.println("New index:" + list.getSelectedIndex()); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { Test t = new Test(); t.setDefaultCloseOperation(t.EXIT_ON_CLOSE); t.setVisible(true); } }); } } Теперь если мы запустим наше приложение из командной строки, то при перемещении по списку мы увидим на экране строку с номером индекса. Но если Вы попробуете изменять строки мышкой, то заметите, что наш метод valueChanged вызывается ДВА раза. Это связано с тем, что список может выделять сразу много строк. В нашем случае нам этот эффект больше мешает, чем помогает. Но мы можем найти на него управу - оказывается объект класса ListSelectionEvent имеет метод getValueIsAdjusting который возвращает true если событие вызывается по причине выбора нескольких пунктов. Нам интересен момент, когда этот метод возвращает false - нам же не надо отслеживать многострочные выделения внутри нашего списка. Поэтому наш пример немного изменится. import java.util.*; import javax.swing.*; import javax.swing.event.*; // Обратите внимание, что теперь наша форма реализует интерфейс public class Test extends JFrame implements ListSelectionListener { private JList list; public Test() { // Для инициализации списка нам потребуется вектор - посмотрите коллекции Vector v = new Vector(); v.add("1"); v.add("2"); v.add("3"); v.add("4"); v.add("5"); list = new JList(v); // Вот здесь выставляем режим выделения одного пункта list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); // Список будет посылать сообщения форме list.addListSelectionListener(this); // Добавляем список на панель формы getContentPane().add(new JScrollPane(list)); // Устанавливаем границы setBounds(100, 100, 200, 200); } // Единственный метод, который реализует интерфейс ListSelectionListener public void valueChanged(ListSelectionEvent e) { if (!e.getValueIsAdjusting()) { System.out.println("New index:" + list.getSelectedIndex()); } } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { Test t = new Test(); t.setDefaultCloseOperation(t.EXIT_ON_CLOSE); t.setVisible(true); } }); } } Теперь давайте попробуем изменять наш список динамически. Если вы будете пробовать просто добавлять в наш вектор какие-либо значения, то эффекта на экране вы не увидите. Вернее может и увидите, но что там точно будет гарантировать я не могу. Как уже упоминалось, нам надо действовать через модель. Модель можно получить вызовом JList.getModel(). Этот метод возвращает нам не класс, а интерфейс ListModel. Конечно же за ним кроется какой-то настоящий класс, но в том удобство и состоит, что вы можете написать свою модель, которая обязана реализовать интерфейс ListModel по своему вкусу, и расширить его теми функциями, которые Вам необходимы. Давайте напишем пример, который будет добавлять в наш список строки. Предварительно сделаем вот какое замечание - наш список на самом деле уже имеет некоторую модель. Но она не является стандартной и что она умеет точно - мы не знаем. В пакете SWING есть уже готовая модель, которая умеет то, что нам надо - а именно добавлять строки. Это DefaultListModel. Давайте ее и используем. Кроме этого мы добавим кнопку, которая будет давать команду на добавление. Для "прослушивания" событий от кнопки нам надо реализовать интерфейс ActionListener. В нем тоже всего один метод - actionPerformed. import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; // Обратите внимание, что теперь наша форма реализует интерфейс public class Test extends JFrame implements ListSelectionListener, ActionListener { private JList list; private JButton add = new JButton("Add"); public Test() { list = new JList(); // Вот здесь выставляем режим выделения одного пункта list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); // Создадим модель и отдади ее нашему списку вместо его стандартной DefaultListModel dlm = new DefaultListModel(); list.setModel(dlm); // Список будет посылать сообщения форме list.addListSelectionListener(this); // Кнопка тоже будет посылать сообщения форме add.addActionListener(this); // Добавляем список на панель формы getContentPane().add(new JScrollPane(list), BorderLayout.CENTER); // Добавляем кнопку в нижнюю часть getContentPane().add(add, BorderLayout.SOUTH); // Устанавливаем границы setBounds(100, 100, 200, 200); } // Единственный метод, который реализует интерфейс ListSelectionListener public void valueChanged(ListSelectionEvent e) { if (!e.getValueIsAdjusting()) { System.out.println("New index:" + list.getSelectedIndex()); } } public void actionPerformed(ActionEvent e) { // Мы знаем, что у списка модель класса DefaultListModel // И поэтому можем ее привести к такому типу DefaultListModel dlm = (DefaultListModel) list.getModel(); // Модель позволяет добавить новый элемент dlm.addElement(String.valueOf(dlm.getSize())); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { Test t = new Test(); t.setDefaultCloseOperation(t.EXIT_ON_CLOSE); t.setVisible(true); } }); } } И наконец напишем пример, которы не только добавляет, но и удаляет. Для этого добавим еще одну кнопку. Заметьте, что обработчик для обеих кнопок будет один и тот же. Для того, чтобы узнать какая кнопка нажата будем использовать методы getName/setName. В примере есть одно неудобство - Вам надо каждый раз при удалении выделять строку которую вы хотите удалить. Но рещение этой проблемки автор оставляет для читателя. А здесь мы приведем окончательный результат нашей работы. import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; // Обратите внимание, что теперь наша форма реализует интерфейс public class Test extends JFrame implements ListSelectionListener, ActionListener { private JList list; public Test() { list = new JList(); // Вот здесь выставляем режим выделения одного пункта list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); // Создадим модель и отдади ее нашему списку вместо его стандартной DefaultListModel dlm = new DefaultListModel(); list.setModel(dlm); // Список будет посылать сообщения форме list.addListSelectionListener(this); JButton add = new JButton("Add"); JButton del = new JButton("Del"); // Кнопка тоже будет посылать сообщения форме add.addActionListener(this); del.addActionListener(this); // Дадим нашим кнопкам имена, чтобы их можно было различать // при обработке add.setName("add"); del.setName("del"); // Создадим панель для наших кнопок и сделаем ее layout // в виде таблицы - 1 строка, 2 столбца JPanel p = new JPanel(); p.setLayout(new GridLayout(1, 2)); p.add(add); p.add(del); // Добавляем список на панель формы getContentPane().add(new JScrollPane(list), BorderLayout.CENTER); // Добавляем панель в нижнюю часть getContentPane().add(p, BorderLayout.SOUTH); // Устанавливаем границы setBounds(100, 100, 200, 200); } // Единственный метод, который реализует интерфейс ListSelectionListener public void valueChanged(ListSelectionEvent e) { if (!e.getValueIsAdjusting()) { System.out.println("New index:" + list.getSelectedIndex()); } } public void actionPerformed(ActionEvent e) { // Мы знаем, что у списка модель класса DefaultListModel // И поэтому можем ее привести к такому типу DefaultListModel dlm = (DefaultListModel) list.getModel(); JButton sender = (JButton) e.getSource(); if (sender.getName().equals("add")) { dlm.addElement(String.valueOf(dlm.getSize())); } // Проверяем имя для удаления и проверяем индекс - если он =-1, // значит нет выделенной строки if (sender.getName().equals("del") && list.getSelectedIndex() >= 0) { dlm.remove(list.getSelectedIndex()); } } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { Test t = new Test(); t.setDefaultCloseOperation(t.EXIT_ON_CLOSE); t.setVisible(true); } }); } } Для сборки нам потребуется команда
javac Test.java Теперь вы готовы к более сложным испытаниям, а именно к работе с наши отделом кадров. В следующей части мы с вами создадим более интересный интерфейс, чем тот, который был создан ренее. Представляем - Часть 5 - Улучшаем интерфейс и вводим команды Архив с исходными кодами: Исходный код |