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

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

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

395

}

public boolean getScrollableTracksViewportHeight() { return false;

}

}

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

new Runnable() {

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

}

}

Пример совсем прост: мы создаем окно с рамкой небольших размеров и размещаем в нем панель прокрутки, в которой, в свою очередь, размещается специальный компонент GridComponent, реализованный в виде внутреннего класса. Сам по себе новый компонент также прост: он унаследован от панели JPanel и переопределяет процедуру прорисовки paintComponent(), в которой рисуется сетка черного цвета. Размеры и количество ячеек сетки (одинаковые по вертикали и горизонтали) задаются специальными переменными. В каждой ячейке также выводится текст с ее координатами, чтобы вам было проще отслеживать процесс прокрутки. Обратите внимание, что непосредственно перед прорисовкой ячеек (которая выполняется в двойном цикле по осям X и Y) необходимо вызвать метод paintComponent() базового класса, в противном случае компонент будет рисоваться неверно3. В панели JPanel, от которой унаследован наш компонент, свойство непрозрачности включено по умолчанию, поэтому перед прорисовкой нужно закрашивать панель цветом фона или очищать ее от «мусора» каким-либо другим способом. Это и делает метод базового класса. Также нам необходимо указать размер нового компонента (по умолчанию размеры компонентов нулевые). Для этого мы переопределяем метод getPreferredSize() и прямо в нем вычисляем размер нашего компонента.

Но самое интересное в том, как компонент GridComponent реализует особый режим прокрутки с помощью интерфейса Scrollable. Как мы уже отмечали, когда панель прокрутки JScrollPane обнаруживает, что размещенный в ней компонент реализует данный интерфейс, она настраивает процесс прокрутки согласно информации, возвращаемой описанными в нем методами. Давайте кратко опишем методы Scrollable (табл. 13.4), а заодно поясним, как эти методы действуют на компонент

GridComponent.

Таблица 13.4. Методы интерфейса Scrollable

Метод

Предназначение

getPreferredScrollableViewportSize()

Возвращает предпочтительный размер для области про-

 

крутки данного компонента. Как правило, этот размер со-

 

впадает с предпочтительным размером самого компонента,

 

как в нашей программе, но бывают и исключения. За при-

 

мером долго ходить не надо — можно вспомнить раскры-

 

вающийся список JComboBox, который выводит перечень

 

своих элементов именно в панели прокрутки.

 

 

3 Детали процесса рисования компонентов Swing всегда можно найти в Главе 4.

396

ГЛАВА 13

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

 

 

 

Метод

Предназначение

 

 

 

С помощью свойства maximumRowCount вы можете огра-

 

ничить количество выводимых элементов, даже если есть

 

возможность вывести на экран их все. Роль ограничителя

 

играет размер, возвращаемый данным методом: больше

 

этого размера область прокрутки не станет (конечно, если

 

ее не заставит это сделать какой-нибудь менеджер распо-

 

ложения). Обычно данный параметр употребляется боль-

 

шими компонентами, которые даже при наличии достаточ-

 

ного пространства предпочитают занимать небольшую его

 

часть, а остальное показывать за счет прокрутки

getScrollableUnitIncrement()

Данный метод возвращает приращение (в пикселах), на

 

которое должно сместиться изображение в панели про-

 

крутки, когда пользователь нажимает кнопку полосы про-

 

крутки (и тем самым «заказывает» переход к следующему

 

логическому элементу компонента). Как и следовало ожи-

 

дать, в нашем примере мы возвращаем размер ячейки

 

сетки — на самом деле, сетку логичнее всего прокручивать

 

по одной ячейке. В качестве параметров данного метода

 

выступают видимая в данный момент часть изображения,

 

ориентация полосы прокрутки JScrollBar (вертикальная

 

или горизонтальная) и тип прокрутки (назад или вперед,

 

соответственно, положительное или отрицательное чис-

 

ло). Проанализировав данные параметры, вы сможете

 

реализовать очень «тонкую» прокрутку, зависящую от по-

 

зиции изображения и направления прокрутки

getScrollableBlockIncrement()

Возвращает приращение (в пикселах) при прокрутке «бло-

 

ком». Подобное приращение происходит, когда пользова-

 

тель щелкает на полосе прокрутки, а не нажимает ее кноп-

 

ки. В нашем примере блок состоит из 10 ячеек и не зависит

 

от параметров. Параметры данного метода аналогичны

 

параметрам метода предыдущего, на их основании вы так-

 

же сможете возвращать различные приращения в зависи-

 

мости от позиции изображения и направления прокрутки

getScrollableTracksViewportWidth(),

Параэтихметодоввозвращаетбулевызначения, которыегово-

getScrollableTracks

рят, зависитлисодержимоекомпонента, находящегосявобла-

ViewportHeight()

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

 

оширинеобластипрокрутки, второй— овысоте). Означаетэто

 

буквальноследующее: вместотогочтобыположитьсянамеха-

 

низмпрокруткиинеменятьсвойразмерприизмененииразме-

 

ров контейнера компонент следит за изменениями размеров

 

и соответственным образом меняет свое содержимое, чтобы

 

оно в доступные размеры помещалось. Как правило, методы

 

этивозвращаютtrue толькопоотдельности, таккакфактически

 

это означает отказ от прокрутки — компонент вместо этого за-

 

являет, что постарается вместить содержимое в то простран-

 

ство, что ему доступно. Чаще всего эти методы применяются

 

там, гдекомпонентотказываетсяотпрокруткипоодномуизна-

 

правлений, вертикальному или горизонтальному. Прекрасный

 

пример — текстовое поле с переносом по словам. Несмотря

 

на то, что вертикальная прокрутка такому полю нужна, гори-

 

зонтальная ему уже не понадобится, так как слова переносят-

 

ся автоматически и длина строки может быть любой

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

397

Запустив программу с примером, вы оцените особый режим прокрутки созданного нами компонента-«сетки», и теперь всегда сможете без особых трудностей реализовать специальный режим для собственных компонентов.

Как правило, требуется особое поведение прокрутки не так уж и часто: в Swing богатейший набор стандартных компонентов, а те из них, что нуждаются в особых режимах прокрутки, уже реализуют интерфейс Scrollable и прокручиваются так, как нужно.

Компонент JViewport

Если вы думаете, что процесс прокрутки полностью управляется панелью прокрутки JScrollPane, то ошибаетесь. На самом деле компонент JScrollPane — не более чем удобный «фасад»4 для целой системы, занимающейся прокруткой вашего компонента. Эта система состоит из специальным образом расположенных5 вспомогательных компонентов для прокрутки, вертикальной и горизонтальной полос прокрутки, заголовков и «уголков» панели. Отображение лишь части от целого компонента и переход к другим его частям лежит на плечах компонента JViewport, основного рабочего «винтика» системы прокрутки, предоставленной нам Swing.

Компонент JViewport удобно представлять себе в виде своеобразного «видоискателя», работающего примерно так же, как в фотоаппарате: имеется общая картина, которую вы хотите запечатлеть (компонент большого размера), но доступного пространства меньше. JViewport позволяет показывать часть компонента и при необходимости перемещаться к любой другой его части. К основным возможностям класса JViewport относится задание компонента для отображения, называемого видом, задание размера области для отображения, называемой видимым диапазоном (extent), а также задание точки левого верхнего угла в области координат вида, с которой

4 Панель прокрутки JScrollPane — прекрасный пример применения шаблона проектирования фасад (facade). Фасад предоставляет простой интерфейс к сложной системе, предположительно составленной из множества различным образом взаимодействующих компонентов.

5 Специальным расположением компонентов, составляющих панель прокрутки, занимается специализированный менеджер расположения ScrollPaneLayout. Вы не сможете установить в панели прокрутки другой менеджер расположения (а если попытаетесь, то непременно наткнетесь на сообщение об ошибке).

398

ГЛАВА 13

и отсчитывается видимая область. Меняя последнюю точку, вы отображаете различные части компонента.

«Видоискатель» JViewport крайне редко применяется изолированно, как правило, вы и не задумываетесь о том, что именно он исправно трудится за кулисами класса JScrollPane, отображая различные части вашего компонента. Иногда, впрочем, особенно если вы реализуете нестандартный способ прокрутки или вам нужно отображать часть компонента, не затрагивая остальных частей панели прокрутки, компонент JViewport может быть полезен и сам по себе. В следующем примере мы познакомимся с ним поближе, отобразив с его помощью части большой надписи:

//UsingViewport.java

//Работа с "видоискателем" JViewport import javax.swing.*;

import java.awt.*;

public class UsingViewport extends JFrame { public UsingViewport() {

super("UsingViewport"); setDefaultCloseOperation(EXIT_ON_CLOSE);

//надпись с текстом большого размера

JLabel bigLabel = new JLabel(

"<html><h1>Большая Надпись!<br>Много текста!");

//"видоискатель"

JViewport viewport = new JViewport();

//устанавливаем вид и видимый диапазон viewport.setView(bigLabel); viewport.setExtentSize(new Dimension(100, 60));

//точка начала видимой области viewport.setViewPosition(new Point(50, 50));

//ограничим размер "видоискателя" viewport.setPreferredSize(new Dimension(100, 60));

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

setLayout(new FlowLayout()); add(viewport);

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

}

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

new Runnable() {

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

}

}

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

399

В примере у нас имеется надпись большого размера (в том, что она большого размера, можно не сомневаться: мы создали ее с помощью встроенного языка HTML, написав пару строк текста большим заголовком — H1). С помощью «видоискателя» JViewport легко отобразить на экране только часть нашей большой надписи, причем любую часть любого размера.

В классе JViewport определен только один конструктор — конструктор по умолчанию (без параметров). После создания компонента JViewport необходимо провести его настройку. Прежде всего задается собственно компонент (называемый видом), который будет отображать «видоискатель», за это отвечает свойство view. Затем необходимо указать, область какого размера будет показывать компонент JViewport (если вы хотите увидеть его в действии, размер видимой области должен быть меньше, чем размер вида). Установить размер видимой области позволяет свойство extentSize. Ну и наконец, остается задать точку левого верхнего угла (в координатах вида), с которой будет начинаться видимая область (свойство viewPosition). Обратите внимание еще на пару нюансов примера: в качестве менеджера расположения панели содержимого мы устанавливаем менеджер FlowLayout и вручную указываем предпочтительный размер компонента JViewport — он будет совпадать с размером видимой области. Эти два действия гарантируют, что сам компонент JViewport не станет больше видимой области вида. В противном случае, если ему хватит места (а в нашем окне ему места хватит), он отобразит весь компонент вне зависимости от настройки. В проведенных дополнительных мерах нет ничего удивительного: JViewport обычно используется при нехватке места в контейнере, поэтому нам пришлось организовать эту нехватку искусственно.

Запустив программу с примером, вы увидите, как созданный и настроенный нами «видоискатель» JViewport отображает лишь часть большой надписи. Именно так он и используется панелью прокрутки JScrollPane: отображает большой компонент, а когда пользователь щелкает на полосах прокрутки, панель прокрутки JScrollPane говорит «видоискателю», что надо сменить координаты левого верхнего угла изображения (viewPosition) и прорисовать новую его часть6. Подобные действия вы сможете проводить и сами, если возникнет необходимость в написании собственной процедуры прокрутки. Например, вам может понадобиться сделать ее подобием прокрутки в известных продуктах компании Apple. Вам придется продумать систему ускорения и замедления прокрутки для создания нужного визуального эффекта, а вот заменять «видоискатель» JViewport при этом вряд ли понадобится: он прекрасно справляется со своей задачей.

JViewport можно задействовать и при создании интерактивной справочной системы в качестве «видеокамеры», плавно перемещающейся по пользовательским интерфейсам вашего приложения. Вариантом может быть размещение всей панели содержимого вашего главного окна в компоненте JViewport, отключение от него всех событий от пользователей с помощью класса JXLayer, который был нами изучен в главе 6, и перемещение «видоискателя» по интерфейсу в зависимости от раздела справки.

6 Получить используемый в JScrollPane «видоискатель» можно с помощью метода getViewport().

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