Создание мастеров настройки на ISBL

5 0

Действует для версии: DIRECTUM 4.5 (IS-Builder 7.6.1) и выше.

Введение

Данный документ описывает алгоритм создания мастеров настройки на языке ISBL. Мастер - это программа, в определенной последовательности вызывающая диалоги, которые запрашивают у пользователя различные параметры, проверяют их корректность и предпринимают соответствующие действия по настройке чего-либо. Все строки, используемые в примерах в данном документе, не локализованы. Это сделано исключительно для того, чтобы упростить понимание кода.

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

Разработка решения

Кнопки диалогов

Для начала опишем все кнопки, используемые в диалогах мастера, например:

  CancelButton   = "Отмена"
  NextButton     = "Далее >>"
  PreviousButton = "<< Назад"
  ReadyButton    = "Готово"

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

Группы кнопок

Добавим код:

  Delimiter = "|"

 

Если один и тот же набор кнопок предполагается использовать в различных диалогах, необходимо определить для него отдельную переменную, например:

  // Кнопки первого диалога (отсутствует кнопка “<< Назад”)  FirstPageButtons = Join(ArrayOf(NextButton; ReadyButton; CancelButton); Delimiter) 
  // Кнопки промежуточного диалога (есть все кнопки)  InnerPageButtons = Join(ArrayOf(PreviousButton; NextButton; ReadyButton;     CancelButton); Delimiter)
  // Кнопки последнего диалога (отсутствует кнопка “Далее >>”)  LastPageButtons  = Join(ArrayOf(PreviousButton; ReadyButton; CancelButton);     Delimiter)

Имя переменной должно оканчиваться на "Buttons".

 

Типы запрашиваемых параметров

Определим все возможные типы параметров, которые запрашиваются диалогами.

В первую очередь задаются простые типы, например:

  StringType = "Строка" 
  IntegerType = "
Число"

  DateType = "Дата"
  FontNameType = “Строка:50

Далее - перечислимые, например:

  taLeft = "По левому краю"
  taRight = "По правому краю"
  TextAlignmentType = Format('Признак:%s,%s:К'; ArrayOf(taLeft; taRight))

Имя переменной, описывающей тип, должно оканчиваться на "Type".

Индексы полей и диалогов

Определим диалоги и параметры, используемые в мастере, и сопоставим с ними порядковые номера. Для диалога порядковый номер определяет, каким по счету он будет отображен пользователю. Для параметра - каким он окажется в списке параметров соответствующего диалога. Например:

  // Стиль текста документа
  TextStyle = 0
    // Имя штрифта
    tsFontName = 0
    // Размер шрифта
    tsFontSize = tsFontName + 1
    // Выравнивание
    tsAlignment = tsFontSize + 1
  // Параметры сохранения документа
  Destination = TextStyle + 1
    // Имя файла
    dPath = 0

Индекс первого диалога должен быть равен 0. Для удобства добавления новых диалогов, индекс каждого последующего диалога должен вычисляться путем прибавления 1 к индексу предыдущего. Аналогично для параметров.

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

Добавим код:

  EnvironmentValueVariableName = 'Value'

Опишем проверки корректности значений всех параметров. Каждая проверка - это ISBL-код, возвращающий результат проверки в переменной Result. Из кода доступна переменная окружения EnvironmentValueVariableName, содержащая значение проверяемого параметра. Например:

  // Параметр пройдет проверку, если его значение не пустое
  ValueIsNotEmptyCondition = Format(
     'Value = Object.Environment.ValueByName("%s");
     
Result = Value <<>> ""'; ArrayOf(EnvironmentValueVariableName))

Имя переменной, описывающей проверку, должно оканчиваться на "Condition".

Условия отображения диалогов

Добавим код:

 

  EnvironmentDialogsVariableName = 'Dialogs'

 

Зададим условия отображения для каждого диалога. Условие представляет собой ISBL-код, возвращающий в переменной Result True, если диалог должен быть отображен, или False - в противном случае. Из кода доступна переменная окружения EnvironmentDialogsVariableName, содержащая полное описание всех диалогов (подробнее см. раздел "Диалоги"). Например:

  // Шаблон условия для проверки поля произвольного диалога на определенное значение
  // В шаблон должны быть подставлены следующие величины:
  //   - EnvironmentDialogsVariableName;
  //   - индекс диалога, содержащего проверяемый параметр;
  //   - FieldValues;
  //   - индекс проверяемого параметра;
  //   - значение, с которым будет сравниваться проверяемый параметр;
  CheckDialogFieldConditionTemplate =
   'Dialogs = Object.Environment.ValueByName("%s")
    Dialog = Dialogs[%s]
    DialogFieldValues = Dialog[%s]
    Result = DialogFieldValues[%s] == "%s"'
  
// Диалог будет отображен, если параметр tsAlignment диалога TextStyle будет равен taLeft
  TextIsLeftAlignedCondition = Format(CheckDialogFieldConditionTemplate; Arrayof(EnvironmentDialogsVariableName; TextStyle; FieldValues; tsAlignment; taLeft))

Имя переменной, описывающей условие, должно оканчиваться на "Condition".

Диалоги

Опишем диалоги мастера в массиве Dialogs, имеющем следующую структуру:

  Dialogs = ArrayOf( 
    // <Диалог1>    ArrayOf(
      // Заголовки параметров      Join(ArrayOf(
        <Заголовок_параметра1>;
        <Заголовок_параметра2>;
        ...
        ); Delimiter);
      // Типы параметров      Join(ArrayOf(
        <Тип_параметра1>;
        <Тип_параметра2>:
        ...
        ); Delimiter);
      // Текущие значения параметров      ArrayOf(
        <Значение_параметра1>;
        <Значение_параметра2>;
        ...
      );
      // Проверки корректности введенных значений параметров      ArrayOf(
        <Проверка_параметра1>;
        <Проверка_параметра2>;
        ...
        );
      // Сообщения о вводе некорректных значений параметров      ArrayOf(
        <Сообщение_параметра1>;
        <Сообщение_параметра2>;
        ...
      );
      // Группа кнопок или перечисление отдельных кнопок:
      //   ArrayOf(
      //     <Кнопка1>;
      //     <Кнопка2>;
      //     ...
      //     );
      <Группа_кнопок>;
      // Заголовок окна диалога      <Заголовок_окна>
      // Условия отображения диалога      ArrayOf(
        <Условие_отображения1>;
        <Условие_отображения1>;
        ...);
      // Способ объединения условий отображения диалога:
      //   - mOr (логическое “Или”)
      //   - mAnd (логическое “И”)
      <Способ_объединения_условий_отображения>
      );   
// <
Диалог2>

    ...
    ) 

 

Для доступа к отдельным частям диалога (текущим значениям параметров, заголовку окна диалога и т.д.) объявим переменные:

  // Заголовки параметров
  FieldCaptions = 0
  // Типы параметров
  FieldTypes = FieldCaptions + 1
  // Текущие значения параметров
  FieldValues = FieldTypes + 1
  // Проверки корректности введенных значений параметров
  FieldChecks = FieldValues + 1
  // Сообщения о вводе некорректных значений параметров
  FieldCheckMessages = FieldChecks + 1
  // Кнопки 
 
Buttons = FieldCheckMessages + 1

  // Заголовок окна диалога
  Title = Buttons + 1
  // Условия отображения диалога
  ExecutionConditions = Title + 1
  // Способ объединения условий отображения диалога
  ExecutionConditionMergeMode = ExecutionConditions + 1

Пример чтения/записи значения параметра:

  // Считать значение параметра dPath диалога Destination
  // Получить диалог
  Dialog = Dialogs[Destination]
  // Получить список значений параметров диалога
  DialogFieldValues = Dialog[FieldValues]
  // Прочитать значение параметр dPath
  ... = DialogFieldValues[dPath]
   // Изменить значение параметра dPath диалога Destination
  DialogFieldValues[dPath] = ...
  // Сохранить изменения
  Dialog[FieldValues] = DialogFieldValues
  Dialogs[Destination] = Dialog

Логика работы

Добавим код, реализующий логику работы мастера по введенным ранее настройкам:

  // Код отмены работы мастера
  ConfigurationFail = -1
  // Код завершения работы мастера
  ConfigurationComplete = -2
  // Код рестарта текущего диалога
  DialogRestarted = -3
  // Индекс текущего диалога
  CurrentDialog = 0
  // Нажатая в последнем диалоге кнопка
  ChosenButton = NextButton
  // Индекс первого диалога
  FirstDialogIndex = ArrayLowBound(Dialogs)
  
// Индекс последнего диалога
  LastDialogIndex = ArrayHighBound(Dialogs)
  // Вызывть диалог с индексом CurrentDialog, пока этот индекс не выдет за
  // диапазон FirstDialogIndex..LastDialogIndex или работа мастера не будет
  // отменена (ConfigurationFail) или завершена (ConfigurationComplete)
 
  while (CurrentDialog <> ConfigurationFail) and
    (CurrentDialog <> ConfigurationComplete) and
    (CurrentDialog >= FirstDialogIndex) and (CurrentDialog <= LastDialogIndex)
  // Получить текущий диалог
    
Dialog = Dialogs[CurrentDialog]
  // Проверить условия отображения текущего диалога
    NeedToExecute = Dialog[ExecutionConditionMergeMode] = mAnd
    Object.Environment.SetVar(EnvironmentDialogsVariableName; Dialogs)
    foreach Condition in CArrayElement(Dialog[ExecutionConditions])
      if Dialog[ConditionsMergeMode] = mAnd
     
   NeedToExecute = NeedToExecute and Execute(Condition)
      else
        NeedToExecute = NeedToExecute or Execute(Condition)
      endif
    endforeach
  
// Если диалог должен быть отображен
    
    if NeedToExecute
   
// Отобразить диалог
       DialogResult = InputDialogEx(Dialog[FieldCaptions]; Join(Dialog[FieldValues];
        Delimiter); Dialog[FieldTypes]; Dialog[Title]; ; ; ; Dialog[Buttons];
        IfThen(CurrentDialog = LastDialogIndex; ReadyButton; NextButton);CancelButton)
    // Считать значения параметров, заданных в ходе работы диалога
       
DialogFieldValues = Dialog[FieldValues]
       
FieldIndex = 0
       FieldsCount = SubStringCount(DialogResult; Delimiter)
       
foreach FieldValue in CSubString(DialogResult; Delimiter)
       
  if FieldIndex = FieldsCount - 1
           // Считать нажатую кнопку
  
         ChosenButton = FieldValue
         
else
           // Считать новое значение параметра
           DialogFieldValues[FieldIndex] = FieldValue
         endif
         FieldIndex = FieldIndex + 1
  
     endforeach
       Dialog[FieldValues] = DialogFieldValues
       Dialogs[CurrentDialog] = Dialog
    // Проверить корректность ввода параметров
    DialogFieldChecks = Dialog[FieldChecks]
    DialogFieldCheckMessages = Dialog[FieldCheckMessages]
    FieldIndex = 0
    
foreach FieldValue in CArrayElement(DialogFieldValues)
      Object.Environment.SetVar(EnvironmentValueVariableName; FieldValue)
      if not Execute(DialogFieldChecks[FieldIndex])
        ShowMessage(DialogFieldCheckMessages[FieldIndex])
        CurrentDialog = DialogRestarted
        exitfor
  
    endif
 
     FieldIndex = FieldIndex + 1
    
endforeach
  endif
       
   
//
Обработать нажатия на кнопки
    
    if ChosenButton == NextButton
     
      CurrentDialog = CurrentDialog + 1
    
    endif
    
    if ChosenButton == PreviousButton
     
      CurrentDialog = CurrentDialog - 1
    
    endif
    
    if ChosenButton == CancelButton
     
      CurrentDialog = ConfigurationFail
     
    endif
    
    if ChosenButton == ReadyButton
          
  CurrentDialog = ConfigurationComplete
         endif
       endwhile

 

Если в диалогах присутствуют какие-либо нестандартные кнопки (отличные от "Далее >>", "<< Назад", "Отмена", "Готово"), необходимо написать для них собственные обработчики, например:

  // Обработать нажатие на кнопку “Выбрать папку”
  if ChosenButton == BrowseButton
    // Создать внешний диалог выбора папки
    FolderDialog = CreateFolderDialog()
    // В качестве начальной папки означить текущее значение параметра dPath
    FolderDialog.InitialDir = DialogFieldValues[dPath]
    // Если пользователь выбрал какую-либо папку
    if FolderDialog.Execute
      // Изменить значение параметра dPath

      DialogFieldValues[dPath] = FolderDialog.Result
      Dialog[FieldValues] = DialogFieldValues
      Dialogs[CurrentDialog] = Dialog
  
  endif
  endif

Настройка

В самом конце необходимо написать код для настройки того, для чего собственно и предназначался создаваемый мастер. Пример чтения/записи значений параметров, которые ввел, приведен в разделе "Диалоги".

Пока комментариев нет.

Авторизуйтесь, чтобы написать комментарий