Мир ПК, #10/1998
|
Постоянный адрес статьи: http://www.osp.ru/pcworld/1998/10/134.htm
|
Библиотека Swing: кнопки17.10.1998
В современных графических интерфейсах кнопкам отводится большая роль, поэтому библиотека Swing содержит несколько кнопочных классов. Общее для всех кнопок поведение задает абстрактный класс AbstractButton. Важные данные компонента и интерфейс к ним хранятся в классе кнопочной модели DefaultButtonModel, реализующем методы интерфейса ButtonModel. Это еще один неявный "кнопочный родственник". От AbstractButton наследуются два основных кнопочных класса: JButton и JToggleButton. Первый служит для создания обычных кнопок с разнообразными возможностями, а второй - для создания радиокнопок (класс JRadioButton) и отмечаемых кнопок (класс JCheckBox). Помимо названных, от AbstractButton наследуется пара классов JCheckBoxMenuItem и JRadioButtonMenuItem, используемых для организации тех меню, пункты которых должны быть оснащены отмечаемыми и радиокнопками. Обычная кнопка Класс JButton библиотеки Swing для создания обычных кнопок предлагает несколько различных конструкторов: JButton() JButton(String) JButton(Icon) JButton(String, Icon) Если используется конструктор по умолчанию, т. е. без параметров, то вы получаете абсолютно пустую кнопку. Задав текстовую строку, получите кнопку с надписью. Для создания кнопки с рисунком передайте конструктору ссылку на класс пиктограммы. Класс JButton содержит несколько десятков методов, основные из которых приводятся в табл. 1, а для того чтобы была более понятна техника их использования, просмотрите листинг 1. Эта маленькая программа базируется на шаблоне, показанном в ╧ 8/98 "Мира ПК" (с. 183, листинг 1). N.B. Обратите внимание на использование пустой рамки шириной в 15 пикселов, выполненной на основе класса EmptyBorder. Она придает программе эстетичный вид. В примере, показанном в листинге 1, для размещения компонентов используется менеджер GridBagLayout. Если вы регулярно программируете на Java, то наверняка знакомы с ним, в противном случае обратитесь к документации по JDK. N.B. Мы не задаем жестко размер окна, а позволяем виртуальной машине Java сделать его оптимальным. А для этого внутри метода main вызывается метод pack, после чего размер окна фиксируется вызовом метода setResizable. При вызове конструктора класса JButton инициализируется ссылка jbtn. В качестве параметра ему передается строка в кодировке UNICODE, задающая надпись "Образцово-показательная кнопка". Для наглядности инициализация главной кнопки jbtn вынесена в отдельный метод setupButton. Внутри этого метода кнопке присваиваются пиктограммы для нормального, выключенного и нажатого состояний. Затем определяется пиктограмма, отображаемая в том случае, если указатель мыши находится непосредственно над кнопкой. И наконец, с помощью метода setToolTipText кнопке присваивается текст "всплывающей" подсказки. Отмечаемая кнопкаКласс JCheckBox, как и класс обычной кнопки JButton, наследует методы абстрактной кнопки AbstractButton, поэтому большую часть методов JCheckBox вы найдете в табл. 1. Однако в силу функциональных особенностей у отмечаемой кнопки имеются методы, управляющие флагом включения/выключения (табл. 2). С помощью отмечаемых кнопок осуществляется управление главной кнопкой jbtn. Поэтому в программу добавлен специальный внутренний класс-адаптер IL, реализующий интерфейс слушателя ItemListener, вызываемый при изменении состояния компонента. Обработка переключения отмечаемых кнопок происходит внутри метода itemStateChanged класса IL. При создании отмечаемых кнопок к каждой из них вызовом метода addItemListener подключается экземпляр класса-адаптера. Вслед за этим кнопка переводится в состояние "отмечено" с помощью метода setSelected. Заглянем внутрь метода itemStateChanged. Когда пользователь включил или выключил отмечаемую кнопку, производится обработка события, для чего сначала получается ссылка на только что переключенную пользователем кнопку: Затем мы получаем ссылку на модель главной кнопки jbtn: Теперь необходимо выяснить, в какое состояние перешла отмечаемая кнопка: Дальше все просто. Нужно определить, какая из кнопок сгенерировала событие: методом getText() считывается текст с отмечаемой кнопки, затем вызываются нужные методы, изменяющие состояние главной кнопки. Следует особо отметить, как обрабатывается переключение кнопки Released. Если ее выключить, то главная кнопка jbtn должна перейти в нажатое состояние. Казалось бы, для программного нажатия достаточно вызвать метод setPressed класса JButton. Однако это не так. N.B. Программное нажатие произойдет лишь в том случае, если заранее был вызван метод setArmed. Запустите пример и потестируйте его, включая и отключая различные опции, задаваемые отмечаемыми кнопками. РадиокнопкиРадиокнопки - их еще иногда называют кнопками с зависимой фиксацией - применяются исключительно в группах. В один момент времени включенной может быть только одна кнопка: как только пользователь включает другую кнопку, та кнопка, которая была включена до этого, выключается. Библиотека Swing для создания радиокнопок содержит конструкторы класса JRadioButton: JRadioButton() JRadioButton(Icon) JRadioButton(Icon, boolean) JRadioButton(String) JRadioButton(String, boolean) JRadioButton(String, Icon) JRadioButton(String, Icon, boolean) Параметры типа String задают надпись на кнопке, а параметры типа Icon определяют рисунок, который будет отображен вместо стандартного, рисуемого по умолчанию. Начальное состояние (включено/выключено) задается параметром конструктора, который имеет тип boolean. При значении true кнопка включается, а при false - выключается. Методы класса JRadioButton практически совпадают с методами отмечаемых кнопок класса JCheckBox. Однако использовать радиокнопки несколько сложнее, поскольку они должны быть объединены в группы. А перед этим группа должна быть создана. Библиотека Swing содержит специальный класс ButtonGroup, от которого нам требуется всего три метода:
Создав экземпляр класса ButtonGroup, надо последовательно вызывать метод add для каждой из радиокнопок, сгруппировать их. Пример, показанный в листинге 2, демонстрирует использование радиокнопок. В окне программы отображается рисунок, а имя файла рисунка определяется включенной радиокнопкой. Имена файлов изображений произвольные, поэтому вы можете задать свои собственные, слегка подправив текст программы. В качестве элемента пользовательского интерфейса, отвечающего за показ рисунков, используется класс JLabel. Вызывая метод setIcon этого класса, мы выводим заданное изображение в окно программы. Расположен метод setIcon непосредственно в обработчике события itemStateChanged, возникающего при переключении группы радиокнопок. Когда обработчик срабатывает, метод getItem класса ItemEvent получает ссылку на включенную кнопку, а уже по этой ссылке запрашивается присвоенный данной кнопке текст. Остается загрузить файл изображения в память и передать его экземпляру класса JLabel для отображения: jlbl.setIcon(new ImageIcon ".\\Icons\\" + ((JRadioButton)e. getItem()).get Text())); Кнопки JCheckBoxMenuItem и JRadioButtonMenuItemБиблиотека Swing предлагает воспользоваться новыми возможностями. Так, теперь вы сможете добавить к пунктам меню отмечаемые и радиокнопки. Это очень удобно, особенно когда вы создаете пункты меню для настройки опций приложения. Меню с отмечаемыми кнопками можно сделать, воспользовавшись классом JCheckBoxMenuItem, для которого определены следующие конструкторы: JCheckBoxMenuItem() JCheckBoxMenuItem(Icon) JCheckBoxMenuItem(String) JCheckBoxMenuItem(String, Icon) JCheckBoxMenuItem(String, boolean) JCheckBoxMenuItem(String, Icon, boolean) Как и в случае с другими кнопками, описанными ранее, аргументы типа String задают надпись для пункта меню, Icon - отображаемый в меню рисунок, boolean - включение/выключение кнопки меню. Меню с радиокнопками создается конструкторами на базе класса JCheckBoxMenuItem: JRadioButtonMenuItem() JRadioButtonMenuItem(Icon) JRadioButtonMenuItem(String) JRadioButtonMenuItem(String, Icon) Назначение параметров конструкторов такое же, как и у всех кнопок библиотеки Swing. Как реализовать меню с кнопками, видно из листинга 3. В данном примере сначала изготавливается полоса меню. Для этого оператором new нужно создать экземпляр класса JMenuBar: После этого на основе класса JMenu формируются раскрывающиеся меню: private JMenu cbmenu = new JMenu("\u041c\u0435\u043d\u044e"); ... private JMenu rbmenu = new JMenu("\u041a\u0440\u0430\u043d"); Затем с помощью классов JCheckBoxMenuItem и JRadioButtonMenuItem создаются пункты выбора: private JCheckBoxMenuItem cbitem1 = new JCheckBoxMenuItem("1 \u0411\u043b\u044e\u0434\u043e"); private JCheckBoxMenuItem cbitem2 = new JCheckBoxMenuItem("2 \u0411\u043b\u044e\u0434\u043e"); private JCheckBoxMenuItem cbitem3 = new JCheckBoxMenuItem("3 \u0411\u043b\u044e\u0434\u043e"); ... private JRadioButtonMenuItem rbitem1 = new JRadioButtonMenuItem("\u041e\u0442\u043a\u0440\u044b\u0442\u044c"); private JRadioButtonMenuItem rbitem2 = new JRadioButtonMenuItem("\u0417\u0430\u043a\u0440\u044b\u0442\u044c");
Затем в меню добавляются пункты выбора, а само меню добавляется в полосу меню программы: cbmenu.add(cbitem1); cbmenu.add(cbitem2); cbmenu.add(cbitem3); cbitem1.setSelected(true); bar.add(cbmenu); ... group.add(rbitem1); group.add(rbitem2); rbmenu.add(rbitem1); rbmenu.add(rbitem2); rbitem1.setSelected(true); bar.add(rbmenu);
При этом пункты меню с радиокнопками добавляются в кнопочную группу group точно так же, как обычные радиокнопки на основе класса JRadioButton. И завершается инициализация программы вызовом специального метода, подключающего полосу меню к окну программы: setJMenuBar(bar); Для каждого элемента меню можно задать собственный рисунок взамен стандартного, предлагаемого библиотекой Swing, и тогда внешний вид меню изменится до неузнаваемости. Таким образом средства библиотеки Swing позволяют внести элемент творчества в такую рутинную работу, как создание пользовательского интерфейса. Листинг 1. Пример использования кнопок JButton и JCheckBox import com.sun.java.swing.*; import com.sun.java.swing.border.*; import java.awt.*; import java.awt.event.*; public class Sample extends JFrame { String[] labels = { "Enabled", "Rollover", "Released", "Draw focus", "Draw border" }; private GridBagLayout gbl = new GridBagLayout(); private GridBagConstraints lc = new GridBagConstraints(); private JPanel jp = new JPanel(gbl); private JButton jbtn = new JButton( "\u041e\u0431\u0440\u0430\u0437\u0446" + "\u043e\u0432\u043e-\u043f\u043e\u043a\u0430\u0437" + "\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f " + "\u043a\u043d\u043e\u043f\u043a\u0430"); public Sample(String caption) { super(caption); try { UIManager.setLookAndFeel( UIManager.getCrossPlatformLookAndFeelClassName()); } catch(Exception e){e.printStackTrace();}; jp.setBorder(BorderFactory.createEmptyBorder(15,15,15,15)); lc.gridheight = 5; lc.weightx = 1.0; lc.weighty = 1.0; lc.fill = GridBagConstraints.BOTH; setupButton(); jp.add(jbtn, lc); lc.gridx = 1; lc.weightx = 0; lc.weighty = 0; lc.insets = new Insets(0, 15, 0, 0); lc.gridheight = 1; lc.anchor = GridBagConstraints.NORTH; for(int i = 0; i < labels.length; i++) { JCheckBox cb = new JCheckBox(labels[i]); cb.addItemListener(new IL()); cb.setSelected(true); jp.add(cb, lc); } setContentPane(jp); } void setupButton() { jbtn.setIcon(new ImageIcon(".\\Icons\\normal.gif")); jbtn.setDisabledIcon(new ImageIcon(".\\Icons\\disabled.gif")); jbtn.setPressedIcon(new ImageIcon(".\\Icons\\pressed.gif")); jbtn.setRolloverIcon(new ImageIcon(".\\Icons\\rollover.gif")); jbtn.setToolTipText( "\u0412\u0441\u043f\u043b\u044b\u0432\u0430\u044e" + "\u0449\u0430\u044f \u043f\u043e\u0434\u0441\u043a" + "\u0430\u0437\u043a\u0430 - \u043e\u0431\u044b" + "\u0447\u043d\u043e\u0435 \u0434\u0435\u043b\u043e " + "\u0434\u043b\u044f Swing"); } private class IL implements ItemListener { public void itemStateChanged(ItemEvent e) { JCheckBox cb = (JCheckBox) e.getItem(); ButtonModel bm = jbtn.getModel(); boolean state; if(e.getStateChange() == ItemEvent.SELECTED) state = true; else state = false; if(cb.getText().equals("Enabled")) jbtn.setEnabled(state); if(cb.getText().equals("Rollover")) jbtn.setRolloverEnabled(state); if(cb.getText().equals("Released")) { bm.setArmed(true); bm.setPressed(!state); } if(cb.getText().equals("Draw focus")) jbtn.setFocusPainted(state); if(cb.getText().equals("Draw border")) jbtn.setBorderPainted(state); } } public static void main(String[] args) { Sample s = new Sample( "\u0411\u0438\u0431\u043b\u0438\u043e \u0442\u0435\u043a\u0430Swing"); s.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); s.pack(); s.setResizable(false); s.setVisible(true); } } Листинг 2. Пример использования кнопок JRadioButton import com.sun.java.swing.*; import com.sun.java.swing.border.*; import java.awt.*; import java.awt.event.*; public class Sample extends JFrame { String[] labels = { "normal.gif", "disabled.gif", "pressed.gif", "rollover.gif" }; private ButtonGroup group = new ButtonGroup(); private GridBagLayout gbl = new GridBagLayout(); private GridBagConstraints lc = new GridBagConstraints(); private JPanel jp = new JPanel(gbl); private JLabel jlbl = new JLabel(); public Sample(String caption) { super(caption); try { UIManager.setLookAndFeel( UIManager.getCrossPlatformLookAndFeelClassName()); } catch(Exception e) {e.printStackTrace();}; jp.setBorder(BorderFactory.createEmptyBorder(15,15,15,15)); lc.gridheight = 4; lc.weightx = 1.0; lc.weighty = 1.0; lc.fill = GridBagConstraints.BOTH; jp.add(jlbl, lc); lc.gridx = 1; lc.weightx = 0; lc.weighty = 0; lc.insets = new Insets(0, 15, 0, 0); lc.gridheight = 1; lc.anchor = GridBagConstraints.NORTH; for(int i = 0; i < labels.length; i++) { JRadioButton rb = new JRadioButton(labels[i]); rb.addItemListener(new IL()); group.add(rb); jp.add(rb, lc); if(i == 0) rb.setSelected(true); } jlbl.setPreferredSize(new Dimension(100, 100)); setContentPane(jp); } private class IL implements ItemListener { public void itemStateChanged(ItemEvent e) { if(e.getStateChange() == ItemEvent.SELECTED) jlbl.setIcon(new ImageIcon( ".\\Icons\\" +((JRadioButton)e.getItem()). getText())); } } public static void main(String[] args) { Sample s = new Sample( "\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 Swing"); s.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); s.pack(); s.setResizable(false); s.setVisible(true); } } Листинг 3. Пример использования кнопок меню import com.sun.java.swing.*; import com.sun.java.swing.border.*; import java.awt.*; import java.awt.event.*; public class Sample extends JFrame { private ButtonGroup group = new ButtonGroup(); private JMenuBar bar = new JMenuBar(); private JMenu cbmenu = new JMenu("\u041c\u0435\u043d \u044e"); private JCheckBoxMenuItem cbitem1 = new JCheckBoxMenuItem("1 \u0411\u043b\u044e\u0434 \u043e"); private JCheckBoxMenuItem cbitem2 = new JCheckBoxMenuItem("2 \u0411\u043b\u044e\u0434 \u043e"); private JCheckBoxMenuItem cbitem3 = new JCheckBoxMenuItem("3 \u0411\u043b\u044e\u0434 \u043e"); private JMenu rbmenu = new JMenu("\u041a\u0440\u0430 \u043d"); private JRadioButtonMenuItem rbitem1 = new JRadioButtonMenuItem( "\u041e\u0442\u043a\u0440\u044b\u0442\u044c"); private JRadioButtonMenuItem rbitem2 = new JRadioButtonMenuItem( "\u0417\u0430\u043a\u0440\u044b\u0442\u044c"); public Sample(String caption) { super(caption); try { UIManager.setLookAndFeel( UIManager.getCrossPlatformLookAndFeelClassName()); } catch(Exception e){e.printStackTrace();}; cbmenu.add(cbitem1); cbmenu.add(cbitem2); cbmenu.add(cbitem3); cbitem1.setSelected(true); bar.add(cbmenu); group.add(rbitem1); group.add(rbitem2); rbmenu.add(rbitem1); rbmenu.add(rbitem2); rbitem1.setSelected(true); bar.add(rbmenu); setJMenuBar(bar); } public static void main(String[] args) { Sample s = new Sample( "\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 Swing"); s.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); s.setSize(300,200); s.setResizable(false); s.setVisible(true); } } |
Мир ПК, #10/1998
|
Постоянный адрес статьи: http://www.osp.ru/pcworld/1998/10/134.htm
|