Диапазоны значений |
355 |
дом setStringPainted(true), и задаем нестандартный текст с помощью метода setString(). Текст, несмотря даже на то, что индикатор является вертикальным, может быть порядочного размера: текст прорисовывается так же, как и сам индикатор, то есть вертикально. Впрочем, стоит заметить, что читать в таком положении длинный текст не слишком удобно (может заболеть шея). Длинный текст лучше оставить для горизонтальных индикаторов, а в вертикальных ограничиться чем-то лаконичным, вроде символа процентов.
После настройки модели и индикаторов нужно добавить последние в панель содержимого нашего окна и вывести окно на экран. Так мы и делаем. Если больше ничего не предпринимать, индикаторы процесса застынут на отметке в пять процентов (помните, текущее значение модели изначально у нас равно пяти, а максимальное — ста, так что все справедливо) и будут малоинтересны. Действительно, в любом приложении, использующем индикаторы, должен быть некоторый процесс, по мере выполнения которого текущее значение индикатора непрерывно обновляется. Роль такого процесса в нашем примере сыграет внутренний класс LongProcess, созданный на основе инструмента SwingWorker и, следовательно, представляющий собой отдельный поток выполнения с возможностью вызова промежуточных действий в графическом потоке рассылке событий. В реальных приложениях процессом может быть загрузка данных из сети или файла с диска, установка компонентов или сетевых соединений, и еще много самых разных действий. Мы сразу же запускаем нашу задачу (вызывая метод execute()), и параллельно с потоком рассылки событий начинает выполняться ее метод doInBackground(). Работа задачи проста: пока текущее значение модели не превышает максимального (то есть пока наш воображаемый процесс не закончен), в цикле while текущее значение увеличивается на единицу, после чего процесс «засыпает» на случайный промежуток времени, а затем все повторяется. Случайный промежуток простоя процесса внесет в пример свою изюминку: вы увидите, как индикатор то бежит быстрее, то замедляется. Обратите внимание, что нам не приходится заботиться о синхронизации: мы применяем метод publish() для вызова кода из потока рассылки событий, передавая туда текущее значение для модели, и работаем с моделью, а не с компонентом, так что модель сама оповестит все присоединенные к ней виды о том, что пора обновить изображение. Просто и эффектно. Не забывайте, что работа с моделью, несмотря на то, что вы не работаете с графическими компонентами напрямую, подразумевает отсылку событий этим компонентам, и, соответственно, их обновление. Так что с моделями работать необходимо только из потока рассылки событий.
Напоследок выпишем все самые полезные свойства индикаторов JProgressBar, использованные нами в примере, чтобы они всегда были «под рукой» и могли послужить простым справочником (табл. 12.2).
356 |
ГЛАВА 12 |
Таблица 12.2. Основные свойства индикаторов JProgressBar |
|
|
|
Свойства |
Описание |
orientation |
Управляеториентациейиндикатора. Ориентацияможетбытьвертикальнойили |
|
горизонтальной. Чаще всего это свойство задается при создании индикатора |
|
инеменяетсявпоследствии. Еслижевыменяетеориентациюдлякомпонента, |
|
которыйуженаходитсянаэкране, незабудьтепровестипроверкукорректности |
|
контейнера: смена ориентации повлияет на расположение компонентов |
stringPainted |
Позволяет включить или выключить прорисовку текста на индикаторе про- |
|
цесса. По умолчанию прорисовка текста выключена. Если вы ее включаете, |
|
то стандартно будет прорисовываться значение в процентах, показываю- |
|
щее, какая часть процесса закончена (значения берутся из модели). Сме- |
|
нить текст позволяет следующее свойство |
string |
Задаеттекст, которыйбудетпрорисовыватьсянаиндикаторепроцесса. Неза- |
|
бывайте только включать прорисовку текста: по умолчанию она отключена |
value, maximum, |
Эти свойства позволяют манипулировать данными модели Bounded- |
minimum |
RangeModel напрямуюспомощьюсамогоиндикатора(модельвлюбомслучае |
|
есть, данные свойства просто делегируют ей свою работу). Управляют соот- |
ветственно текущим, максимальным и минимальным значениями. Благодаря
им (а также благодаря конструкторам JProgressBar, которые сразу позволяют
задатьэтизначенияинеявносоздают стандартнуюмодель) высможетеработать с индикатором так, как будто модели вовсе и нет. Впрочем, преимущества моделей нам прекрасно известны, так что лучше ее задействовать
Описанных свойств индикаторов вполне хватает для большей части приложений: роль этих компонентов на самом деле невелика. Используются они именно так, как было показано нами в примере: есть отдельный поток выполнения с долгими вычислениями, который обновляет модель (конечно же, из потока рассылки событий), а индикатор каждое изменение исправно отображает на экране.
Когда ничего не ясно
Бывают (и, надо сказать, довольно часто) ситуации, когда сказать точно, сколько осталось до завершения процесса и на каком этапе он в данный момент находится, вы не в состоянии. В таких случаях не слишком удобно использовать индикатор: непонятно, каковы же значения модели и как их обновлять. С другой стороны, лишать пользователя хоть какого-то намека на то, что процесс идет, тоже не следует. В расчете на такие ситуации индикаторы процесса JProgressBar поддерживают состояние «неопределенности»: периодическое движение на полосе есть, но, сколько осталось до конца, не ясно. В том случае, если процесс переходит в более «определенное» состояние, и вы, наконец, сможете выяснить, на каком этапе он находится и с какой скоростью продвигается, индикатор можно перевести в обычное состояние, которое нам уже знакомо. Давайте рассмотрим «неопределенный» пример:
//IndeterminateProgressBars.java
//Индикаторы в состоянии "неопределенности" import javax.swing.*;
import java.awt.*;
public class IndeterminateProgressBars extends JFrame { public IndeterminateProgressBars() {
Диапазоны значений |
357 |
super("IndeterminateProgressBars"); setDefaultCloseOperation(EXIT_ON_CLOSE); // неопределенный индикатор
JProgressBar progress = new JProgressBar(0, 100); progress.setIndeterminate(true); progress.setStringPainted(true);
// добавляем его в окно и выводим на экран setLayout(new FlowLayout());
add(new JLabel("Соединение:")); add(progress);
setSize(300, 200); setVisible(true);
}
public static void main(String[] args) { SwingUtilities.invokeLater(
new Runnable() { public void run() {
new IndeterminateProgressBars(); } });
}
}
В панель содержимого окна мы добавляем индикатор JProgressBar, у которого нет даже самой простой отдельной модели: нам помогает конструктор, позволяющий задать минимальное и максимальное значения, а стандартная модель будет создана автоматически, за кулисами. Большего нам не понадобится: индикатор в состоянии неопределенности не использует никаких данных модели. Как видно из примера, состояние «неопределенности» включается свойством indeterminate. Никаких действий предпринимать больше не требуется: индикатор сам позаботится о том, чтобы вид полосы периодически менялся, изображая продолжающуюся деятельность процесса и подбадривая этим пользователя. Дополнительно мы включили прорисовку текста свойством stringPainted, он появится даже в «неопределенном состоянии» (по умолчанию будет изображаться выполненная в процентах часть процесса — в зависимости от значения, установленного в модели). Однако чаще всего «неопределенное» состояние не использует стандартное отображение в процентах, как дополнительное подтверждение того, что на данный момент информация о выполнении процесса отсутствует. Лучше заменить строку на свою собственную, которая подчеркнет что процесс занимает неопределенное время. Запустив программу с примером, вы сможете оценить, как смотрится «неопределенная» ситуация в исполнении индикатора JProgressBar.
Пример довольно реален: сетевые соединения зачастую не позволяют сказать определенно, что именно произошло и когда возобновится прием информации.
358 |
ГЛАВА 12 |
Небольшие хитрости
Индикаторы процесса на самом деле очень просты, и работа с ними сводится в основном к обновлению текущего значения модели. Даже их внешний вид толком не настраивается (изменить можно лишь отображаемую индикатором строку). Впрочем, с помощью некоторых незамысловатых свойств UI-представителя индикаторов JProgressBar, не попавших в класс самого компонента, вы сможете добиться более изысканных визуальных эффектов, в некоторых случаях больше отвечающих стилю вашего приложения. Свойства эти отвечают за вид полосы индикатора. Рассмотрим небольшой пример, в котором эти свойства будут использоваться для достижения нового внешнего вида:
//ProgressBarTricks.java
//Небольшие хитрости индикаторов процесса import javax.swing.*;
import java.awt.*;
public class ProgressBarTricks extends JFrame { // максимальное значение индикатора
private final int MAX = 100; public ProgressBarTricks() { super("ProgressBarTricks");
setDefaultCloseOperation(EXIT_ON_CLOSE);
//настроим параметры для UI-представителей
UIManager.put("ProgressBar.cellSpacing", 2); UIManager.put("ProgressBar.cellLength", 6);
//стандартная модель
final DefaultBoundedRangeModel model =
new DefaultBoundedRangeModel(0, 0, 0, MAX);
//создадим простой индикатор процесса
//на основе полученной модели
JProgressBar progress = new JProgressBar(model);
//добавим его в окно setLayout(new FlowLayout()); add(progress);
//выводим окно на экран setSize(300, 200); setVisible(true);
//создадим "процесс"
Thread process = new Thread(new Runnable() { public void run() {
//увеличиваем текущее значение модели до
//достижения максимального значения
int value = 0;
while ( ++value <= MAX ) {
Диапазоны значений |
359 |
final int passValue = value; SwingUtilities.invokeLater(
new Runnable() { public void run() {
model.setValue(passValue); }});
try { Thread.sleep(200);
} catch (Exception ex) { }
}
}
}); // запустим поток
process.start();
}
public static void main(String[] args) { SwingUtilities.invokeLater(
new Runnable() {
public void run() { new ProgressBarTricks(); } });
}
}
Здесь мы создаем небольшое окно, в котором разместится незатейливый индикатор процесса. Данные этому индикатору будет поставлять стандартная модель, начальное значение ее равно нулю, минимальное также равно нулю, а максимальное значение равно ста (вы можете видеть, как мы задаем значения в конструкторе модели). Самое интересное происходит в паре строк, которые настраивают внутренние свойства UIпредставителей индикаторов процесса (а мы знаем, что именно эти представители и выполняют фактическую прорисовку компонента на экране). Свойства UI-представителей всех компонентов Swing для любого внешнего вида хранятся в специальной таблице класса UIManager, и мы можем менять их, используя методы put(). Оказывается, что с помощью данных свойств можно тонко настроить внешний вид индикаторов процесса (точнее, перемещающейся в них полосы). Свойство с названием cellLength управляет тем, какой длины будут ячейки полосы индикатора (полоса индикатора не обязательно прорисовывается сплошной, она может состоять из набора ячеек одинакового размера), а свойство cellSpacing задает расстояние между ячейками (если это расстояние приравнять нулю, то полоса будет сплошной). Запустив программу с примером, вы увидите, как описанные два свойства влияют на внешний вид индикатора процесса (в современных пользовательских интерфейсах более популярны именно такие, ячеистые, индикаторы). Правда, стоит иметь в виду, что данные свойства действуют, только если в индикаторе процесса не прорисовывается информационная строка. Если строка есть, то полоса индикатора будет сплошной в любом случае.