Афоризм
Большому кораблю – большие в трюме крысы.
Наталья Резник
Последние статьи

 • Активности Android
Многоэкранные Android приложения
 • Fragment dynamic
Динамическая загрузка фрагментов в Android
 • Fragment lifecycle
Жизненный цикл Fragment'ов в Android
 • Fragment example
Пример Fragment'ов в Android
 • Data Binding
Описание и пример Data Binding
 • Пример MVVM
Пример использования MVVM в Android
 • Компонент TreeTable
Описание компонента TreeTable для Swing
 • Пример TreeTable
Пример использования TreeTable
 • Хранилища Android
Внутренние и внешние хранилища данных
 • Пример SQLite
Пример использования SQLite в Android
 • WebSocket
Описание и пример реализации WebSocket
 • Визуальные компоненты
Улучшен компонент выбора даты из календаря
 • Анимация jQuery
Описание и примеры анимации элементов DOM
 • APK-файл Android
Создание apk-файла для android устройств, .dex файлы
 • платформа JaBricks
Платформа OSGi-приложения JaBricks
Поддержка проекта

Если Вам сайт понравился и помог, то будем признательны за Ваш «посильный» вклад в его поддержку и развитие
 • Yandex.Деньги
  410013796724260

 • Webmoney
  R335386147728
  Z369087728698

Сохранение и восстановление значений компонентов

При описании примеров использования базовых модулей формирования интерфейса (base-jdialog, base-jpanel, base-universal) было отмечено, что при закрытии формы/панели, т.е. при остановке бандла, регулируемые настройки интерфейса сохраняются во внешнем файле. При повторном открытии формы/панели интерфейсные настройки восстанавливаются. К интерфейсным настройкам относятся положения разделителей JSplitPane и размеры колонок таблицы JTable, а для jdialog дополнительно размеры окна.

Вместе с регулируемыми настройками во внешнем файле сохраняются значения интерфейсных компонентов модулей, созданных с использованием базовых модулей base-universal и gui-widgets. Для чего это нужно? Ну, конечно же, для восстановления значений компонентов при повторном старте. А теперь разберем данный тезис подробнее.

Представим себе приложение, которое имеет много различных форм, создаваемых различными интерфейсными бандлами. Естественно, все формы невозможно разместить на одном экране. Необходимо какие-то скрывать, а какие-то открывать. Для реализации данного функционала необходимо иметь хороший диспетчер, который бы «управлял этим оркестром». То есть, диспетчер должен одному из бандлов при старте или при переводе его в активное состояние передать главный контейнер приложения для размещения своего интерфейса, а интерфейс другого бандла «убрать» с экрана (из контейнера). А если интерфейсный бандл интегрирует в свою форму интерфейс одного или нескольких бандлов? В этом случае, необходимо контролировать функционирование сразу нескольких бандлов. Задача может усложниться ещё и тем, что каждый бандл может загрузить в интерфейс большой объём информации. Кто-то может сказать, что сейчас компьютеры мощные и за ресурсы можно не волноваться. Можно. Но, во-первых, время переключения между формами может возрасти. Этим можно пренебречь, тем более, что загрузка информации тоже может оказаться «недешевой». Но самое главное, что доступ к интерфейсной части бандла доступен только его активатору, у других бандлов данного доступа просто нет. Поэтому диспетчер должен понимать, какие интерфейсные компоненты какому бандлу принадлежат. Помните, что при останове бандлов необходимо также «убрать» их интерфейс; это прерогатива программиста.

Чтобы не «заморачиваться с диспетчером» платформа JаBricks в базовом модуле base-universal содержит функционал сохранения во внешнем файле значений интерфейсных компонентов вместе с регулируемыми настройками и методы их восстановления при переводе бандла в состояние ACTIVE. Для восстановления значений компонентов при переводе бандла в активное состояние необходимо проверить время сохранения настроек, и, в случае их сохранения после старта приложения, вызвать методы восстановления значений компонентов. Данный функционал реализован в демонстрационном приложении «Домашние финансы», созданным на платформе JaBricks.

Примечание : сохранение и восстановление значений компонентов нужно только для компонентов типа панелей (JPanel), размещаемых в контейнера главного фрейма или интегрируемых в интерфейс другого бандла. Данный сервис можно реализовать в интерфейсных бандлах, наследующих свойства базового модуля base-universal.

Сохранение настроек и значений компонентов

Для сохранения интерфейсных настроек и значений компонентов необходимо переопределить метод активатора 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 и включающего :

  • TemplActivator, активатор, наследует UniversalActivator;
  • TemplPanel, наследует JBPanel и организует создание интерфейсной панели;
  • TemplCommon, наследует JBCommon и формирует интерфейс.

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

  Рейтинг@Mail.ru