410013796724260
• Webmoney
R335386147728
Z369087728698
Сохранение и восстановление значений компонентовПри описании примеров использования базовых модулей формирования интерфейса (base-jdialog, base-jpanel, base-universal) было отмечено, что при закрытии формы/панели, т.е. при остановке бандла, регулируемые настройки интерфейса сохраняются во внешнем файле. При повторном открытии формы/панели интерфейсные настройки восстанавливаются. К интерфейсным настройкам относятся положения разделителей JSplitPane и размеры колонок таблицы JTable, а для jdialog дополнительно размеры окна. Вместе с регулируемыми настройками во внешнем файле сохраняются значения интерфейсных компонентов модулей, созданных с использованием базовых модулей base-universal и gui-widgets. Для чего это нужно? Ну, конечно же, для восстановления значений компонентов при повторном старте. А теперь разберем данный тезис подробнее.
Представим себе приложение, которое имеет много различных форм, создаваемых различными интерфейсными бандлами.
Естественно, все формы невозможно разместить на одном экране. Необходимо какие-то скрывать, а какие-то открывать. Для
реализации данного функционала необходимо иметь хороший диспетчер, который бы «управлял этим оркестром». То есть,
диспетчер должен одному из бандлов при старте или при переводе его в активное состояние передать главный контейнер
приложения для размещения своего интерфейса, а интерфейс другого бандла «убрать» с экрана (из контейнера). А если
интерфейсный бандл интегрирует в свою форму интерфейс одного или нескольких бандлов? В этом случае, необходимо
контролировать функционирование сразу нескольких бандлов. Задача может усложниться ещё и тем, что каждый бандл может
загрузить в интерфейс большой объём информации. Кто-то может сказать, что сейчас компьютеры мощные и за ресурсы можно
не волноваться. Можно. Но, во-первых, время переключения между формами может возрасти. Этим можно пренебречь, тем
более, что загрузка информации тоже может оказаться «недешевой». Но самое главное, что доступ к интерфейсной части
бандла доступен только его активатору, у других бандлов данного доступа просто нет. Поэтому диспетчер должен понимать,
какие интерфейсные компоненты какому бандлу принадлежат. Помните, что при останове бандлов необходимо также «убрать»
их интерфейс; это прерогатива программиста. Сохранение настроек и значений компонентовДля сохранения интерфейсных настроек и значений компонентов необходимо переопределить метод активатора saveComponentParams. Ниже представлен код метода примера templ-universal.
@Override
public void saveComponentParams()
{
if (jdialog != null)
((JDialogForm)jdialog).saveComponentParams();
else if (jpanel != null)
((JPanelForm)jpanel).saveComponentParams();
}
Именование компонентовМетод восстановления значений компонентов restoreComponentsValue класса JBCommon в качестве параметров принимает сам компонент, краткое наименование класса компонента и его наименование. То есть, чтобы восстановливать значение компонента, он должен быть «именован». Поскольку интерфейсная форма может включать несколько однотипных компонентов, то регулируемые настройки и значения сохраняются только у именованных компонентов. Для именования Swing-компонента имеется метод setName (String), позволяющий определять его наименование. Но это касается простых Swing-компонентов. Библиотека компонентов gui-widgets включает виджеты JDatePicker, Grid и Gridp. Каждый виджет содержит один или несколько Swing-компонентов, отображаемых в интерфейсе. Так, например, JDatePicker представляет в интерфейсе компонент JFormattedTextField, Grid представляет таблицу JTable, а Gridp – таблицу JTable и группу компонентов для навигации (пагинатор), значимым из которых является компонент типа JTextField. Таким образом, при использовании в интерфейсе виджета, необходимо именовать его «значимые» Swing-компоненты. Рассмотрим пример интерфейсного бандла, наследующего свойства классов базового модуля base-universal и включающего :
Допустим, интерфейс бандла (класс TemplCommon) включает набор компонентов, представленных в следующем листинге, и методы, рассмотренные ниже. Особый интерес в классе представляют три последних компонента (cbPeriod, dpDate, gridp) :
public class TemplCommon extends JBCommon
{
// Компоненты интерфейса
JTextField tfName ;
JTextArea taNote ;
JCheckBox chkActive;
JRadioButton rbService;
JRadioButton rbGood ;
DoubleField dblPrice ;
JComboBox<Reference> cbPeriod ;
JDatePickerImpl dpDate ;
IGridp gridp ;
// Константные наименования компонентов
String NAME_name = "tfName" ;
String NAME_note = "taNote" ;
String NAME_active = "chkActive";
String NAME_service = "rbService";
String NAME_good = "rbGood" ;
String NAME_price = "dblPrice" ;
String NAME_period = "cbPeriod" ;
String NAME_date = "dpDate" ;
String NAME_gridp = "gridp" ;
...
public void createGUI()
{
...
}
public void restoreComponentsValue()
{
...
}
}
Здесь следует отметить, что компонент cbPeriod использует объект типа Reference из базового модуля base-universal. Это обязательное условие для восстановления значения компонента, чтобы класс JBCommon смог определить выделенное значение. Что касается вопроса создания интерфейса, то он не относится к теме данной статьи, и мы его не будем рассматривать. Рассмотрим только код именования компонентов в методе создания интерфейса createGUI :
public class TemplCommon extends JBCommon
{
...
public void createGUI()
{
// ...
tfName .setName(NAME_name );
taNote .setName(NAME_note );
chkActive.setName(NAME_active );
rbService.setName(NAME_service);
rbGood .setName(NAME_good );
dblPrice .setName(NAME_price );
cbPeriod .setName(NAME_period );
dpDate .getJFormattedTextField()
.setName(NAME_date);
gridp .getTable()
.setName(NAME_gridp);
// ...
}
...
}
Обратите внимание, как именуются два последних компонента (dpDate и gridp). У них именование касается значимых для интерфейса Swing-компонентов. Здесь следует отметить, что gridp помимо таблицы включает дополнительно панель навигации, о которой было отмечено выше. Чтобы учесть возможность останова бандла при нахождении не на первой странице навигации, необходимо также именовать и пагинатор. Особо напрягаться здесь не придётся : виджеты IGrid, IGridp библиотеки компонентов gui-widgets версии 1.0.2 включают методы setGridName, которые именуют одновременно таблицу и пагинатор. Правда, пагинатор имеет то же самое наименование, что и таблица. Но типы компонентов пагинатора и таблицы отличаются, поэтому при сохранении и дальнейшем восстановлении значений данных компонентов они не пересекаются. Для таблиц сохраняются размеры колонок и выделенная строка. Таблица с компонентами JCheckBox дополнительно сохраняет значения выделенных строк. У пагинатора сохраняется активная страница таблицы. Таким образом, для именования табличного компонента из библиотеки base-gui версии 1.0.2 можно использовать следующий код :
gridp.setGridName(NAME_gridp);
Запрос времени активности приложенияДля восстановления значений компонентов в первую очередь необходимо получить время старта приложения для определения активности настроек бандла, стартуемого фреймворком. В течение одного сеанса функционирования бандл может быть несколько раз стартован и остановлен. Для получения времени старта приложения необходимо в методе активатора start выполнить определенную «подписку», пример :
public class TemplActivator extends UniversalActivator
{
@Override
public void start(final BundleContext context)
throws Exception
{
super.start(context);
// Подписка на 'Запрос времени старта' приложения
createStartTimeResponseSubscriber(this);
// Отправка запроса
sendStartTimeRequestEvent();
}
...
}
После этого, используя метод активатора public long getStartTime, можно получить время старта приложения (мс) и определить активность сохраненных данных. Определение активности сохраненных данныхНиже представлен пример класса TemplPanel, конструктор которого получает активатор в качестве параметра. Метод класса createGUI(Container) создает интерфейс и проверяет активность сохраненных настроек вызовом метода isDataActive(). В случае активности сохраненных данных вызывается метод restoreComponentsValue() класса TemplCommon, в котором определены интерфейсные компоненты.
public class TemplPanel extends JBPanel
{
private TepmlActivator activator = null;
private TemplCommon tc = null;
//-----------------------------------------------------
public TemplPanel(TepmlActivator activator)
{
super(activator.getBundleContext());
this.activator = activator;
}
//-----------------------------------------------------
public boolean isDataActive()
{
boolean active = false;
// Время сохранения настроек
Date saved = tc.getSaveDateTime();
// Время старта программы
long start_time activator.getStartTime();
// Время после старта программы
long diff = saved.getTime() - start_time;
active = (diff > 0);
return active;
}
//-----------------------------------------------------
private void createGUI(Container container)
{
// Создание интерфейсной панели
tc = new TemplCommon(context);
// Чтение регулируемых настроек интерфейса
tc.readComponentParams();
// Создание интерфейсной панели : JBCommon.pnlDesk
tc.createDesk();
// Размещаем интерфейсную панель в контейнере
container.add(tc.getPnlDesk());
tc.getPnlDesk().setVisible(false);
if (isDataActive()) {
System.out.println("Data is active");
tc.restoreComponentsValue();
}
// Перенастроить контейнер на новый интерфейс
container.doLayout();
tc.getPnlDesk().doLayout();
tc.getPnlDesk().setVisible(true);
}
}
В представленном примере при создании интерфейса панели будет выполнена проверка активности сохраненных данных, и, при необходимости, восстановлены значения интефейсных компонентов вызовом метода restoreComponentsValue класса TemplCommon, наследника JBCommon. Восстановление настроек и значений компонентовИнтерфейсные настройки и значения компонентов сохраняются во внешнем файла gui/[bundle_name].xml, если, конечно же, переопределен метод активатора saveComponentParams. Непосредственно работать с этим файлом нет необходимости : класс JBCommon базового модуля содержит методы извлечения необходимой информации и восстановления значений компонентов. Структура файла gui/[bundle_name].xml включает время сохранения настроек, значение которого в виде Date можно получить вызовом метода getSaveDateTime класса JBCommon. Сохраненые настройки из файла можно методом readComponentParams() загрузить в переменную cparams типа List<ComponentParams> (см. листинг выше). Для восстановления значения компонента необходимо вызвать метод restoreComponentsValue базового класса JBCommon с передачей ему необходимых параметров :
void restoreComponentsValue(Component component,
String className,
String cmptName);
Восстановление значений компонентовРассмотрим в качестве примера метод restoreComponentsValue интерфейсного класса TemplCommon, наследующего свойства JBCommon. Выше был представлен класс TemplPanel, в котором выполняется создание экземпляра данного класса и вызов его метода restoreComponentsValue :
public void restoreComponentsValue()
{
restoreComponentsValue(tfName,
tfName.getClass().getSimpleName(), NAME_name );
restoreComponentsValue(taNote,
taNote.getClass().getSimpleName(), NAME_note );
restoreComponentsValue(chkActive,
chkActive.getClass().getSimpleName(),NAME_active );
restoreComponentsValue(rbService,
rbService.getClass().getSimpleName(),NAME_service);
restoreComponentsValue(rbGood,
rbGood.getClass().getSimpleName(), NAME_good );
restoreComponentsValue(dblPrice,
dblPrice.getClass().getSimpleName(), NAME_price );
restoreComponentsValue(cbPeriod,
cbPeriod.getClass().getSimpleName(), NAME_period );
restoreComponentsValue(dpDate,
JFormattedTextField.class.getSimpleName(),NAME_date);
// восстановление paginator'a
String cls_name = Paginator.class.getSimpleName();
ComponentParams cp;
cp = extractComponentParams(cls_name, NAME_gridp);
if (cp != null) {
int page = 1;
try {
page = Integer.valueOf(cp.getValue());
if (page > 1)
selectPage(page);
} catch (Exception e) {}
}
// выделение строки таблицы
restoreComponentsValue(gridp.getTable(),
JTable.class.getSimpleName(), NAME_gridp);
}
Листинг метода restoreComponentsValue демонстрирует процесс восстановления значений компонентов интерфейса. Особый интерес здесь представляют последние строки метода, в которых восстанавливается состояние таблицы с панелью навигации. Следует отметить, что сначала необходимо восстановить значение пагинатора при регистрации не первой страницы таблицы. Переопределенный метод selectPage относится к интерфейсу IPaginator, который должен наследовать класс, размещающий в своем интерфейсе таблицу с панелью навигации. Подробно об этом представлено здесь. Метод selectPage должен загрузить в таблицу необходимый набор данных, после чего можно выделить сохраненную запись. |
