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

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

Диапазоны значений

345

Таблица 12.1. Настройка отметок ползунков

 

 

 

Свойство

Значение

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

 

 

majorTickSpacing

Позволяет задать расстояние, через которое будут рисоваться основ-

 

ные (большие) деления или метки (если они должны выводиться)

minorTickSpacing

Задает расстояние, через которое рисуются промежуточные (малень-

 

кие) деления. Логично делать это расстояние меньше, чем предыду-

 

щее, и так, чтобы между большими делениями было кратное количе-

 

ство маленьких делений

paintTicks

Включает или отключает прорисовку делений. Если вы включаете про-

 

рисовку, не забудьте настроить два предыдущих свойства (расстояния

 

между большими и/или маленькими делениями)

paintLabels

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

 

умолчанию выводится значение, соответствующее делению, но как мы

 

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

paintTrack

Управляет выводом на экран полосы (шкалы), по которой перемеща-

 

ется регулятор, меняющий выбранное значение. По умолчанию шкала

 

выводится, и отключать ее не стоит — становится непонятно, к чему

 

относится регулятор. Это свойство может быть полезным если, напри-

 

мер, вы решите создать собственную шкалу, но не захотите писать UI-

 

представителя ползунка «с нуля»

snapToTicks

Мы не использовали данное свойство в примере, но часто оно бывает

 

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

 

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

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

в произвольном месте шкалы. Задействовать это свойство можно там,

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

Используя конструкторы, описанные в примере, и свойства, перечисленные в таблице, можно получить большое количество разнообразных ползунков, вполне достаточное для большинства приложений. Впрочем, как и всегда, Swing не останавливается на полпути, и мы увидим, что ползунки способны на большее.

Модель BoundedRangeModel

Мы уже упомянули о том, что отображаемые ползунком данные хранит модель, описываемая интерфейсом BoundedRangeModel. Она состоит из четырех целых чисел: минимального, максимального и текущего значений, а также внутреннего диапазона (extent). Первые три числа вряд ли нужно объяснять подробно, назначение их понятно, а вот зачем в модели внутренний диапазон? Внутренний диапазон начинается от текущего значения и занимает какой-то числовой интервал, хотя и не может быть больше максимального значения. Он используется не только в ползунках, но и в полосах прокрутки JScrollBar (они также хранят свои данные в модели BoundedRangeModel), где именно внутренний диапазон отвечает за длину полосы прокрутки. Грубо говоря, внутренний диапазон определяет, какая часть от целого в данный момент полностью доступна пользователю (это может быть видимая часть компонента в панели прокрутки JScrollPane). Подробнее мы обсудим полосы прокрутки JScrollBar в главе 13. Ползунки же используют внутренний диапазон, чтобы определить, на сколько должен «прыгнуть» регулятор, если пользователь щелкает на шкале ползунка, не трогая регулятор. Все это иллюстрирует следующая схема:

346

ГЛАВА 12

extent

 

 

 

 

 

 

 

 

 

 

 

 

 

 

min

value

max

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

Помимо хранения и при необходимости изменения (все четыре значения можно изменять, в модели описаны соответствующие методы get/set) четырех целых чисел модель BoundedRangeModel, как и можно было бы ожидать, обязана оповещать присоединенных к ней слушателей об изменениях в этих числах. Для этого она генерирует событие ChangeEvent. Модель BoundedRangeModel также поддерживает специальный режим valueIsAdjusting, в котором она перестает оповещать слушателей об изменениях

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

вобычное состояние и сообщает слушателям об изменении в данных, запуская событие ChangeEvent.

Вы видите, что модель BoundedRangeModel для ограниченных данных очень проста, и реализовывать ее самому вряд ли потребуется. Лучше задействовать класс DefaultBoundedRangeModel — стандартную реализацию, поставляемую вместе с библиотекой Swing. Стандартная модель позволяет задавать и изменять все четыре значения и прекрасно справляется со слушателями. Именно этот класс незаметно для вас создают конструкторы ползунка JSlider, передавая в него те же значения, которые вы передаете им. При этом остаются доступными все достоинства моделей: возможность присоединения модели к нескольким видам, отделение механизмов обработки данных от пользовательского интерфейса, и т. д. Рассмотрим простой пример с двумя ползунками:

//SliderDefaultModel.java

//Использование в ползунках стандартной модели import javax.swing.*;

import java.awt.*;

public class SliderDefaultModel extends JFrame { // наша модель

private BoundedRangeModel model; public SliderDefaultModel() {

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

model = new DefaultBoundedRangeModel(10, 0, 0, 100);

Диапазоны значений

347

JSlider

slider1 = new JSlider(model);

 

JSlider

slider2 = new JSlider(JSlider.VERTICAL);

 

slider2.setModel(model);

//добавляем ползунки в окно setLayout(new FlowLayout()); add(slider1);

add(slider2);

//выводим окно на экран setSize(300, 300); setVisible(true);

}

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

new Runnable() {

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

}

}

Мы создаем стандартную модель DefaultBoundedRangeModel, используя удобный конструктор: в нем сразу задаются текущее значение, внутренний диапазон (он нам не понадобится, а вернее сказать, даже помешает, так что мы задали его равным нулю), а также минимальное и максимальное значения. Далее мы присоединяем модель к двум ползункам. Первый ползунок создается с помощью удобного конструктора, сразу же позволяющего задать модель. Впрочем, это не обязательно: второй ползунок мы создаем конструктором, в котором указываем, что ползунок будет вертикальным, а модель присоединяем позже методом setModel(). После этого ползунки помещаются в окно и появляются на экране.

Запустив программу с примером, вы увидите, как одна модель поставляет данные для двух разных компонентов, так что они меняются синхронно. Достоинства моделей налицо: вы храните в них данные и при необходимости меняете эти данные (или их меняет пользователь), не беспокоясь о правильном отображении или получении измененной информации — это задача вида, то есть компонента JSlider.

События ползунков

Ползунки — очень простые компоненты, поэтому событий у них немного, а точнее одно. Это событие ChangeEvent, запускаемое моделью BoundedRangeModel при изменении пользователем текущего значения ползунка1. С его помощью вы сможете сразу узнавать о перемещении пользователем регулятора и соответствующим образом изменить состояние программы и ее интерфейса согласно новому текущему значению ползунка. Надо сказать, что для ползунков свойственен «мгновенный эффект»: любое перемещение регулятора по шкале ползунка заставляет пользователя смотреть (или слушать, например при перемещении регулятора громкости), что при этом изменилось, так что всегда следует присоединять к ползунку слушателя событий ChangeEvent и сразу же реагировать на изменения, иначе ваша программа рискует стать неудобной и нелогичной.

1 Событие ChangeEvent генерируется также при изменении любого из четырех значений, хранимых в модели (вы легко можете изменить, к примеру, максимальное значение), но это происходит редко, чаще всего пользователю достаточно знать только об изменении текущего значения.

348

ГЛАВА 12

Присоединить слушателя событий ChangeEvent можно либо к модели BoundedRangeModel, используемой в ползунке, либо к самому ползунку JSlider. Разница будет лишь в источнике события, получаемого методом getSource() класса ChangeEvent: в первом случае источником будет модель, а во втором — ползунок. И модель, и ползунок позволяют получить все четыре значения и при необходимости изменить их, так что выбор того или другого — дело вкуса. Рассмотрим небольшой пример:

//SliderEvents.java

//События ползунков import javax.swing.*; import javax.swing.event.*; import java.awt.*;

public class SliderEvents extends JFrame { public SliderEvents() {

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

JSlider slider = new JSlider(0, 900, 0); slider.setMajorTickSpacing(100); slider.setPaintTicks(true);

boost = new JLabel("Ускорение: "); // присоединяем слушателя

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

// меняем надпись int value =

((JSlider)e.getSource()).getValue(); int percent = value/15;

boost.setText("Ускорение: " + percent + " %");

}

});

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

JPanel contents = new JPanel(); contents.add(new JLabel("Размер буфера:")); contents.add(slider);

add(contents); add(boost, "South");

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

setSize(360, 100); setVisible(true);

}

private JLabel boost;

Диапазоны значений

349

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

new Runnable() {

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

}

}

Мы создаем ползунок, позволяющий регулировать размер некоторого буфера (возможно, для сетевого соединения или для воспроизведения звука). При этом с помощью динамически меняющейся надписи вы сможете видеть, какое ускорение можно получить при увеличении размера буфера. Для ползунка мы включаем прорисовку больших делений и присоединяем к нему слушателя события ChangeEvent. Событие ChangeEvent очень «легкое»: в нем не хранится никакой информации за исключением источника события (этому есть свои причины — ChangeEvent запускается так часто, что его пришлось сделать как можно более простым во избежание лишних затрат ресурсов), так что нужно знать, к чему вы присоединяете слушателя ChangeListener. Мы присоединили слушателя к ползунку JSlider, и можем смело преобразовать источник события к объекту JSlider, и с его помощью получить текущее значение. Полученное текущее значение обновляет надпись, так что пользователь мгновенно может оценить, как размер буфера влияет на ускорение, и выбрать оптимальный для него вариант. В заключение ползунок и надписи добавляются в окно (надпись boost на юг окна), и окно выводится на экран.

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

ChangeEvent.

Дополнительная настройка внешнего вида

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

Наиболее полезна возможность создания собственных надписей для определенных значений, отображаемых ползунком. Вы передаете их в метод setLabelTable() в виде подкласса таблицы Dictionary, сопоставляя целому числу («обернутому» в класс Integer) соответствующую надпись, причем в качестве метки (надписи) могут выступать любые компоненты, унаследованные от базового класса JComponent. Это «развязывает вам руки»,

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