В предыдущем примере пользователь мог установить оба флажка, один из них или ни одного. Во многих ситуациях необходимо выбрать только один из предложенных вариантов. Если пользователь установит другой флажок, то предыдущий флажок будет сброшен.
Такую группу флажков часто называют группой переключателей(radio button). Эти кнопки напоминают переключатели диапазонов на радиоприемниках — при нажатии на одной из таких кнопок ранее нажатая кнопка возвращается в исходное состояние.
На рис.1 показан типичный пример окна программы, содержащей группу переключателей. Пользователь может выбрать размер шрифта — Small(Малый), Medium(Средний), Large(Большой) и Extra large(Очень большой). Разумеется, выбрать можно лишь один размер.
Рис.1. Группа переключателей.
Пакет Swing позволяет легко реализовать группы переключателей. Для этого нужно создать для каждой группы по одному объекту ButtonGroup. Затем в группе переключателей необходимо добавить объекты типа JRadioButton. Объект класса ButtonGroup предназначен для того, чтобы отключать ранее выбранный переключатель, если пользователь щелкнул на новой кнопке.
1 2 3 4 5 |
ButtonGroup group = new ButtonGroup(); JRadioButton smallButton = new JRadioButton("Small", false); group.add(smallButton); JRadioButton smallButton = new JRadioButton("Medium", true); group.add(mediumButton); |
Второй параметр конструктора принимает значение true, если изначально переключатель должен быть включен, и false — если выключен. Отметим, что объект типа ButtonGroup управляет лишь поведением переключателей. Если нужно объединить несколько групп переключателей, их следует поместить в контейнер, например объект класса JPanel.
Смотрите на рис.1 и рис.2, обратите внимание что переключатели отличаются по внешнему виду от флажков опций. Флажки опций изображают в виде квадратов, причем для установленных флажков внутри имеется галочка, в то время как переключатели имеют круглую форму: включенные — с точкой внутри, а выключенные — без обозначений.
Механизм извещения о наступлении событий, связанных с переключателями, точно такой же, как и для любых других кнопок. Если пользователь включил переключатель, соответствующий объект генерирует событие. В рассматриваемом здесь примере установлен слушатель, задающий конкретный размер шрифта.
1 2 3 4 5 6 7 8 |
ActionListener listener = new ActionListener(){ public void actionPerformed(ActionListener event) { // Размер шрифта задается последним параметром // метода addRadioButton. label.setFont(new Font("Serif", Font.PLAIN, size)); } }; |
Сравните этот обработчик с обработчиком для флажка опций. Каждому переключателю соответствует свой объект-слушатель. Каждый объект-слушатель точно знает, что нужно делать — установить конкретный размер шрифта.
Для флажков ситуация иная. Оба флажка в нашем примере были связаны с одним и тем же слушателем. Он вызывал метод, определяющий текущее состояние обоих флажков.
Можно ли реализовать такой подход для переключателей? Зададим один слушатель, устанавливающий конкретный размер шрифта:
1 2 3 |
if(smallButton.isSelected()) size = 8; else is(mediumButton.isSelected() size = 12; ... |
Однако предпочтительнее использовать отдельные объекты-слушатели поскольку они более явно связывают размер шрифта с конкретным переключателем.
В группе может быть выбран только один переключатель. Хорошо бы сразу знать, какой именно, не поверяя каждый переключатель в группе. Поскольку объект класса ButtonGroup управляет всеми переключателями, было бы удобно, если бы он давал нам ссылку на выбранный переключатель. Действительно, в классе ButtonGroup есть метод getSelection(), но этот метод не возвращает ссылку на выбранный переключатель.
Вместо этого он возвращает ссылку на объект класса ButtonModel — модель, связанную с этим переключателем. К сожалению, все методы класса ButtonModel не представляют собой ничего ценного. Интерфейс ButtonModel наследует метод getSelectedObjects() из интерфейса ItemSelectable, возвращающий совершенно бесполезную ссылку null.
Метод getActionCommand() выглядит предпочтительнее, поскольку позволяет определить текстовую строку, связанную с переключателем.
Однако команда в модели этого переключателя снова представляет собой нулевую ссылку null. Только если программист явно задаст команды для каждого переключателя с помощью метода setActionCommand(), установив значение, соответствующее каждой команде, впоследствии можно будет определить команду включенного переключателя с помощью метода buttonGroup.getSelection().getActionCommand().
Ниже представлен полный исходный код программы, позволяющий установить размер шрифта с помощью переключателей:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
import java.awt.*; import java.awt.event.*; import javax.swing.*; public class RadioButtonTest { public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { RadioButtonFrame frame = new RadioButtonFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }); } } /** * Фрейм с текстовой меткой и переключателями, * предназначенный для выбора размера шрифта. */ class RadioButtonFrame extends JFrame { public RadioButtonFrame() { setTitle("RadioButtonTExt"); setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); // Добавление метки. label = new JLabel("Самые полезые уроки Java на Pro-Java.ru"); label.setFont(new Font("Serif", Font.PLAIN, DEFAULT_SIZE)); add(label, BorderLayout.CENTER); // Добавление переключателей. buttonPanel = new JPanel(); group = new ButtonGroup(); addRadioButton("Small", 8); addRadioButton("Medium", 12); addRadioButton("Large", 18); addRadioButton("Extra large", 36); add(buttonPanel, BorderLayout.SOUTH); } /** * Добавление переключателей, устанавливающих размер шрифта * для отображения текстовой метки. * @param name Строка, которая помечается кнопка * @param size Размер шрифта для кнопки */ public void addRadioButton(String name, final int size) { boolean selected = size == DEFAULT_SIZE; JRadioButton button = new JRadioButton(name, selected); group.add(button); buttonPanel.add(button); // Слушатель, устанавливающий размер шрифта для метки. ActionListener listener = new ActionListener() { public void actionPerformed(ActionEvent event) { // Размер соответствует последнему параметру метода addRadioButton label.setFont(new Font("Serif", Font.PLAIN, size)); } }; button.addActionListener(listener); } public static final int DEFAULT_WIDTH = 400; public static final int DEFAULT_HEIGHT = 200; private JPanel buttonPanel; private ButtonGroup group; private JLabel label; private static final int DEFAULT_SIZE = 12; } |