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 должен загрузить в таблицу необходимый набор данных, после чего можно выделить сохраненную запись. |