|
Мир ПК, #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
|