Материал: Портянкин И. Swing

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

Управление пространством

375

что язык HTML можно также использовать в тексте подсказки для вкладки, а к тексту ярлычка вкладки нетрудно сразу же присоединить значок, у вас есть отличный способ сообщить пользователю все необходимое о вкладках в вашем интерфейсе, так что ему не придется слишком часто обращаться к системе помощи и работать он сможет гораздо эффективнее.

Созданные панели с вкладками JTabbedPane мы добавляем в наше окно, для которого предварительно устанавливается табличное расположение GridLayout (конструктор GridLayout без параметров позволяет располагать компоненты в одну строку). Благодаря этому окно будет разделено на две одинаковые части, в которых и расположатся наши панели с вкладками. Остается только вывести окно на экран. Запустив программу с примером, вы сможете оценить различные варианты расположения вкладок и их внешний вид, а в случае со второй панелью с вкладками посмотреть на всплывающие подсказки.

Описанные нами параметры панели JTabbedPane и отдельных вкладок можно изменять не только при вызове конструктора или метода addTab(). В классе JTabbedPane все свойства, использованные нами, описаны как свойства JavaBeans с набором методов get/set, так что параметры панели с вкладками и сами вкладки в любой момент нетрудно изменить, вызвав соответствующие методы. Опишем теперь все задействованные нами свойства, чтобы они всегда были у вас «под рукой» (табл. 13.1).

Таблица 13.1. Основные свойства панели с вкладками JTabbedPane

Свойства

Описание

(и методы get/set)

 

tabPlacement

Задает расположение ярлычков вкладок у одной из четырех сторон панели.

 

По умолчанию (если вызывается конструктор JTabbedPane без параметров)

 

ярлычки располагаются вверху панели (TOP). Располагать ярлычки справа

 

или слева лучше, если связанные с вашими вкладками компоненты занима-

 

ют по оси Y больше места, чем по оси X, в противном случае ярлычки удоб-

 

нее поместить сверху или снизу

tabLayoutPolicy

Определяет, как будут располагаться вкладки в том случае, если в контей-

 

нере не хватит места для их размещения в один ряд. Как мы уже отмеча-

 

ли, режим WRAP_TAB_LAYOUT (используемый по умолчанию) позволяет

 

разместить вкладки в несколько рядов, а режим SCROLL_TAB_LAYOUT —

 

оставить их в одном ряду с добавлением кнопки прокрутки. В большинстве

 

случаев пользователю лучше подойдет режим с прокруткой, так как не-

 

сколько рядов вкладок занимают слишком много места на экране (особенно

 

когда вкладок много), что затрудняет переход на нужную вкладку

376

ГЛАВА 13

Таблица 13.1 (продолжение)

 

 

Свойства

Описание

(и методы get/set)

 

titleAt, iconAt

Эти свойства позволяют задать надпись и значок для ярлычка любой вклад-

 

ки (не забывайте о том, что у вас в руках вся «магия» HTML). В качестве пер-

 

вого параметра требуется указать индекс вкладки (отсчет ведется с нуля)

toolTipTextAt

Это свойство отвечает за текст всплывающей подсказки к каждой вкладке.

 

Первым параметром метода также является индекс вкладки.

componentAt

Данное свойство позволяет получить или заменить компонент, который по-

 

казывает вкладка уже после того, как вы настроили ее методом addTab().

 

Не следует путать со свойством tabComponentAt, которое отвечает за саму

 

вкладку и которое мы рассмотрим чуть позже

foregroundAt,

Удобные свойства для задания цвета шрифта и фона отдельной вкладки (ко-

backgroundAt

торая, как нетрудно догадаться, задается индексом). В примере мы не ис-

 

пользовали эти свойства, но иногда они помогают просто и быстро выделить

 

одну из вкладок (или щедро расцветить все вкладки, если это соответствует

 

интерфейсу вашего приложения)

Все свойства панели с вкладками JTabbedPane довольно стандартны, отметить можно лишь необычный формат этих свойств и суффикс «At» в конце их названий. Эти свойства индексированные (в качестве первого параметра методов get/set нужно указывать числовой индекс), так как вкладок в панели может быть много, а свойства надо задавать отдельно для каждой из них. Вам не обязательно добавлять все вкладки и соответствующие им компоненты перед выводом панели с вкладками на экран, это вполне можно делать динамически, прямо во время работы программы, вызывая метод addTab() в нужный момент. Это может пригодиться, если какая-то часть вашего пользовательского интерфейса должна стать доступной позже остальных (хотя, как мы увидим чуть позже, можно отключить вкладку и включать ее при необходимости). Добавлять вкладки можно не только методом addTab(). Вы можете попробовать метод insertTab(), параметры которого аналогичны параметрам метода addTab() и который позволяет вставить вкладку в произвольное место панели JTabbedPane.

Таким образом, обычно работа с панелью JTabbedPane сводится к заданию текста (и/ или значка) для ярлычка вкладки и ее содержимого, в качестве которого чаще всего выступает панель JPanel с группой компонентов вашего пользовательского интерфейса (хотя содержимым вкладки может быть любой компонент, унаследованный от базового класса JComponent). При необходимости в панель нетрудно динамически добавить новые вкладки или изменить все свойства уже имеющихся вкладок.

Модель выделения и обработка событий

Панель с вкладками JTabbedPane чаще всего используется в качестве вспомогательного инструмента, позволяющего эффективно распределить доступное пространство контейнера, и поэтому дополнительные действия с ней проводить требуется крайне редко. На самом деле, вы сопоставляете вкладкам набор компонентов вашего пользовательского интерфейса, а о переключении вкладок вам заботиться не нужно. Когда пользователь переходит на другую вкладку (щелчком мыши или нажатием клавиш), все необходимые действия выполняют внутренние механизмы класса JTabbedPane, так что для программиста все в итоге сводится к выводу панели с вкладками на экран.

Впрочем, при необходимости вы можете расширить «свое сотрудничество» с панелью JTabbedPane и более подробно отслеживать, что с ней происходит. Относится это

Управление пространством

377

прежде всего к переключению вкладок. Вы можете следить за этим и в любой момент времени узнать, какая вкладка активна, поскольку у класса JTabbedPane есть помощник — модель выделения единственного элемента SingleSelectionModel. Эта модель и хранит информацию об активной вкладке и при необходимости (когда ей сообщает об этом UIпредставитель) меняет текущий индекс вкладки. Модель SingleSelectionModel является, пожалуй, самой простой моделью из всех моделей Swing. Она хранит целое число — индекс активной вкладки (когда это число равно —1, считается, что в данный момент активных вкладок нет) и поддерживает методы для присоединения и отсоединения слушателей ChangeListener, которые оповещаются при смене активной вкладки. Действительно, невозможно придумать модель проще. По умолчанию в панели JTabbedPane используется стандартная реализация этой модели, класс с именем DefaultSingleSelectionModel, и вряд ли вам понадобится вмешиваться в его работу или писать свою модель «с нуля». Хранение одного числа не стоит таких усилий, с ним вполне может справиться и стандартная модель. Тем не менее, это самая настоящая модель, так что вы можете разделять ее между несколькими панелями с вкладками, сохраняя в ней информацию о выделенном элементе. Такое поведение может вам пригодится, если у вас в программе есть несколько одинаковых панелей JTabbedPane, активная вкладка в которых должна быть всегда одной и той же.

Единственное событие, поддерживаемое панелью с вкладками JTabbedPane (за исключением низкоуровневых событий, общих для всех графических компонентов), относится именно к модели ее активизации. Добавив к панели JTabbedPane (или к ее модели выделения, это одно и то же, различным будет лишь источник события) слушателя ChangeListener, вы сможете узнавать об активизации следующей вкладки. Практическое применение такому событию придумать непросто, однако оно может быть полезно при реализации разного рода отложенных вычислений. Например, если какая-либо вкладка содержит сложные компоненты, выводить на экран которые дорого и долго, вы можете отложить их создание до того момента, когда пользователь реально перейдет на эту вкладку. Он может этого и не сделать — тогда вы сэкономите его время и ресурсы компьютера. Кроме того, панель JTabbedPane позволяет узнать, в каком месте экрана находится та или иная вкладка, а также к какой вкладке относится некоторая точка экрана. Иногда, при нестандартной обработке событий от мыши, такая возможность бывает полезной, например, при реализации своей системы помощи, когда для каждой вкладки имеются свои советы и свои разделы в справочной системе (прототип подобной системы был создан нами в главе 6).

Создадим несложный пример и посмотрим, как можно использовать события панели с вкладками JTabbedPane:

//TabSelection.java

//Работа с активными вкладками и обработка событий import javax.swing.*;

import javax.swing.event.*; import java.awt.event.*; import java.awt.*;

public class TabSelection extends JFrame { public TabSelection() {

super("TabSelection"); setDefaultCloseOperation(EXIT_ON_CLOSE); // создаем нашу панель с вкладками

JTabbedPane tabs = new JTabbedPane();

378

ГЛАВА 13

tabs.addTab("Вкладка", new JPanel()); tabs.addTab("Еще вкладка", new JPanel()); // добавляем слушателя событий

tabs.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) {

// добавляем на вкладку новый компонент

JPanel panel = (JPanel) ((JTabbedPane)e.getSource()).

getSelectedComponent(); panel.add(new JButton("Кнопка"));

}

}); // работа с низкоуровневыми событиями

tabs.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { // узнаем, на какой вкладке был щелчок int idx = ((JTabbedPane)e.getSource()). indexAtLocation(e.getX(), e.getY());

JOptionPane.showMessageDialog( null, "Index: " + idx);

}

}); // выводим окно на экран

add(tabs); setSize(400, 300); setVisible(true);

}

public static void main(String[] args) { SwingUtilities.invokeLater(

new Runnable() {

public void run() { new TabSelection(); } });

}

}

Здесь мы создаем небольшое окно, в которого добавляем панель с вкладками JTabbedPane. Для создания последней используется конструктор без параметров, так что ярлычки вкладок будут располагаться наверху панели (так принято по умолчанию). Сама панель с вкладками очень проста: мы добавляем в нее только две вкладки, которым сопоставляем пустые панели JPanel (как вы помните, по умолчанию в таких панелях имеет место последовательное расположение FlowLayout). В эти панели мы будем динамически добавлять компоненты. Интереснее посмотреть на то, как к панели с вкладками присоединяются слушатели событий. Первый слушатель (ChangeListener) следит за переходами между вкладками. Можно было бы присоединить его и к модели выделения SingleSelectionModel, но нам в примере удобнее получать в качестве источника события

Управление пространством

379

саму панель с вкладками, так что слушателя мы присоединяем к ней. Когда пользователь переходит на другую вкладку, вызывается метод stateChanged() нашего слушателя, в котором мы определяем источник события (объект JTabbedPane), с помощью удобного метода getSelectedComponent() получаем компонент, соответствующий активной вкладке, преобразуем его к панели JPanel (а мы знаем, что нашим вкладкам соответствуют панели) и добавляем в нее новую кнопку JButton. Таким образом каждый раз при смене вкладки в нее добавляется еще одна кнопка. Не слишком полезное поведение программы, но как мы уже упомянули, в реальных приложениях примерно таким же образом можно реализовать отложенные вычисления.

Далее демонстрируется, как можно работать с панелью JTabbedPane на самом низком уровне. К ней присоединяется слушатель событий от мыши, позволяющий следить за щелчками мыши внутри нашей панели с вкладками. Когда пользователь щелкает мышью где-то на панели с вкладками, нам передаются только координаты щелчка. Определить, на какой вкладке щелкнул пользователь, позволяет метод indexAtLocation(). Он возвращает индекс вкладки, если пользователь щелкнул на вкладке, или —1, если щелчок был не на вкладке, а где-то в другом месте панели. Вы можете применять подобный подход, к примеру, если вам потребуется отдельное выпадающее меню для каждой вкладки, а не единственное меню для компонента JTabbedPane целиком.

Запустив программу с примером, вы сможете увидеть, как панель с вкладками позволяет следить за активной вкладкой и динамически обновлять панель содержимого при переходе на другую вкладку. Вы также сможете увидеть, как работает метод indexAtLocation(), и при случае использовать его в своих программах, хотя такая необходимость возникает редко.

Дополнительные возможности компонента JTabbedPane

Рассмотренных нами возможностей панели с вкладками JTabbedPane с лихвой хватает для ее традиционной работы в хорошем пользовательском интерфейсе: вы можете задавать любые надписи и значки для ярлычков вкладок, сопоставлять с вкладками любые компоненты, следить за изменениями состояния вкладок, и пользователь без затруднений сможет переключаться между вкладками щелчками мыши или нажатиями клавиш (список поддерживаемых панелью JTabbedPane сочетаний клавиш вы можете найти в интерактивной документации Java, эти клавиатурные сокращения практически идентичны для всех стандартных внешних видов). Тем не менее, создатели Swing на этом не остановились и добавили в класс JTabbedPane несколько возможностей, которые помогут сделать ваш пользовательский интерфейс отточенным и продуманным до мелочей.

Очень полезной является возможность задать для вкладки мнемонику, знакомую нам «со времен» изучения глав 8 и 9. Как вы помните, это сочетание управляющей клави-

Источник: https://studfile.net/preview/15935977/