Текущий раздел:

Описания RDS

Руководство программиста

Глава 2. Создание моделей блоков

§2.7. Настройка параметров блока

§2.7.5. Открытие модальных окон средствами Windows API

# Руководство программиста

## Глава 2. Создание моделей блоков

### §2.7. Настройка параметров блока

#### §2.7.5. Открытие модальных окон средствами Windows API

Рассматривается пример модели блока, позволяющего выбрать произвольный цвет при помощи стандартного диалога Windows и выдающего выбранный цвет на выход в виде целого числа. Пример иллюстрирует открытие модальных окон (в данном случае – стандартного диалога) средствами Windows API.

Вспомогательные объекты-окна RDS могут содержать только набор стандартных элементов (простые поля ввода, выпадающие списки, флаги, области рисования и т.п.), расположенных друг под другом на вкладках окна или на боковой панели. Если модели блока этого недостаточно, она должна организовать диалог с пользователем самостоятельно при помощи функций Windows API или каких-либо специальных библиотек. При этом необходимо соблюдать все правила работы с модальными окнами, в частности, информировать RDS об открытии и закрытии модального окна функциями rdsBlockModalWinOpen и rdsBlockModalWinClose. Рассмотрим пример, в котором блок будет открывать модальное окно средствами Windows. Чтобы не загромождать текст модели блока большим количеством вызовов API, не имеющих прямого отношения к RDS, в качестве модального окна будем использовать стандартный диалог выбора цвета. Это один из простейших диалогов, используемых в Windows, он обладает всеми свойствами модального окна и для него не придется писать собственную функцию обработки событий. Создадим блок, который позволяет выбрать цвет с помощью стандартного диалога Windows, и выдает его на свой выход «Color» типа int. Как принято в Windows, младший байт целого числа будет содержать интенсивность красной компоненты цвета, второй байт – интенсивность зеленой, а третий – интенсивность синей (это соответствует структуре стандартного типа COLORREF в Windows API). Для наглядности следует задать для блока векторную картинку, связав цвет какой-нибудь геометрической фигуры (например, прямоугольника) с переменной «Color», в этом случае заданный цвет будет отражаться на внешнем виде блока в режимах моделирования и расчета.

Блок будет иметь следующую структуру переменных:

Смещение | Имя | Тип | Размер | Вход/выход | Пуск | Начальное значение
--- | --- | --- | --- | --- | --- | ---
0 | Start | Сигнал | 1 | Вход | ✓ | 1
1 | Ready | Сигнал | 1 | Выход |  | 0
2 | Color | int | 4 | Выход |  | 0

Поскольку этот блок не имеет личной области данных, не работает с динамическими переменными и не участвует в расчете, его модель будет достаточно простой:

      extern "C" __declspec(dllexport)
        int RDSCALL ModalWindowTest(int CallMode,
                                    RDS_PBLOCKDATA BlockData,
                                    LPVOID ExtParam)
      {
      // Макроопределения для статических переменных
      #define pStart ((char *)(BlockData->VarTreeData))
      #define Start (*((char *)(pStart)))
      #define Ready (*((char *)(pStart+RDS_VSZ_S)))
      #define Color (*((RDSINT32 *)(pStart+2*RDS_VSZ_S)))
        // Вспомогательная структура для работы с диалогом цвета
        CHOOSECOLOR cc;
        // Массив дополнительных цветов для диалога
        static COLORREF CustomColors[16]=
                        {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
        // Возвращаемое функцией модели значение
        int result=RDS_BFR_DONE;
        // Вспомогательная переменная – результат вызова диалога
        BOOL ok;

        switch(CallMode)
          { // Проверка типа переменных
            case RDS_BFM_VARCHECK:
              if(strcmp((char*)ExtParam,"{SSI}")==0)
                return RDS_BFR_DONE;
              return RDS_BFR_BADVARSMSG;

            // Функция настройки
            case RDS_BFM_SETUP:
              // Установка параметров структуры для работы с диалогом
              memset(&cc,0,sizeof(cc));
              cc.lStructSize=sizeof(cc);
              cc.hwndOwner=rdsGetAppWindowHandle();
              cc.lpCustColors=CustomColors;
              cc.rgbResult=Color;
              cc.Flags=CC_RGBINIT;
              // Уведомление RDS об открытии модального окна
              rdsBlockModalWinOpen(NULL);
              // Вызов диалога
              ok=ChooseColor(&cc);
              // Уведомление RDS о закрытии модального окна
              rdsBlockModalWinClose(NULL);
              if(ok) // Пользователь выбрал цвет
                { // Запись цвета в Color
                  Color=cc.rgbResult;
                  // Установка этого значения Color по умолчанию
                  // (2 – порядковый номер переменной Color в блоке)
                  rdsSetBlockVarDefValueByCur(BlockData->Block,2);
                  // Возвращаемое значение должно сигнализировать о наличии изменений в схеме
                  result=RDS_BFR_MODIFIED;
                }
              break;
          }
        return result;
      // Отмена макроопределений
      #undef Color
      #undef Ready
      #undef Start
      #undef pStart
      }
      //=========================================

Для работы с диалогом выбора цвета требуется специальная структура CHOOSECOLOR, поэтому в начале функции модели описана вспомогательная переменная cc этого типа. Перед вызовом диалога в поля этой структуры записываются различные параметры, определяющие вид и поведение диалога, а после закрытия окна из нее можно считать цвет, выбранный пользователем. Кроме этой структуры для работы диалога нужен массив из 16 значений типа COLORREF для хранения цветов, определенных пользователем (подробнее см. описание Windows API). Этот массив также описан в начале функции модели. Он объявлен статическим, чтобы определенные пользователем цвета сохранялись между вызовами диалога и были доступны всем блокам с этой моделью. Дополнительно описывается целая переменная – результат функции модели result, которой исходно присваивается константа RDS_BFR_DONE (если пользователь выберет другой цвет в функции настройки, этой переменной будет присвоено значение RDS_BFR_MODIFIED), и вспомогательная логическая переменная ok, которой позднее будет присвоен результат вызова функции диалога.

При вызове модели в режиме RDS_BFM_VARCHECK переданная строка типа переменных сравнивается со строкой «{SSI}» – кроме двух обязательных сигналов блок должен иметь целую переменную, в которую будет записываться цвет. При вызове функции настройки блока (RDS_BFM_SETUP) прежде всего инициализируется структура сс типа CHOOSECOLOR, необходимая для стандартного диалога выбора цвета. Сначала при помощи функции memset вся структура заполняется нулевыми байтами, после чего в поле lStructSize записывается размер самой структуры. Это обычная практика при работе с Windows API – функция ChooseColor, в которую будет передан указатель на эту структуру, сможет проверить, соответствует ли размер структуры требованиям функции. В поле hwndOwner записывается дескриптор главного окна приложения, полученный при помощи сервисной функции RDS rdsGetAppWindowHandle. Это нужно для того, чтобы открывающееся модальное окно было привязано к главному окну RDS. В поле lpCustColors записывается указатель на статический массив для шестнадцати пользовательских цветов CustomColors, описанный в начале функции модели. В поле rgbResult записывается исходное значение цвета, которое пользователь будет изменять в диалоге, взятое из переменной Color. Наконец, в поле Flags записывается стандартная константа CC_RGBINIT, приказывающая диалогу взять исходное значение цвета из поля rgbResult этой структуры перед открытием окна. Теперь структура сс готова к вызову диалога.

Перед открытием любого модального окна (в данном случае – перед вызовом диалога) необходимо уведомить об этом RDS при помощи функции rdsBlockModalWinOpen. Эта функция принимает единственный параметр – идентификатор блока, открывающего модальное окно. В данном случае окно открывается изнутри функции модели блока, поэтому RDS в состоянии самостоятельно определить, модель какого блока в данный момент работает, и вместо идентификатора блока можно передать значение NULL (при желании можно было явно указать идентификатор этого блока, вызвав функцию с параметром BlockData->Block). Теперь можно открыть окно диалога, вызвав функцию Windows API ChooseColor и передав в нее указатель на структуру cc. Когда пользователь закроет окно, функция вернет TRUE, если он нажал кнопку «OK» (при этом в поле rgbResult структуры cc будет записан выбранный цвет), или FALSE, если он нажал кнопку «Отмена». Возвращенное функцией значение записывается во вспомогательную переменную ok и будет проанализировано позднее. После вызова функции диалога модель информирует RDS о закрытии модального окна при помощи сервисной функции rdsBlockModalWinClose.

Теперь, когда модальное окно закрыто, и RDS знает об этом, можно разобраться с цветом, выбранным пользователем. Если пользователь закрыл окно кнопкой «OK», значение вспомогательной логической переменной ok будет истинно. При этом выбранный пользователем цвет записывается в переменную блока Color из поля структуры cc.rgbResult. Может показаться, что этого достаточно, однако присвоение нового значения переменной Color изменяет только ее текущее значение, которое не запоминается при сохранении схемы. Кроме того, при первом же сбросе расчета переменной Color будет присвоено значение по умолчанию, и выбранный пользователем цвет будет потерян. Чтобы этого не произошло, нужно кроме текущего значения переменной Color изменить еще и ее значение по умолчанию. Для этого используется сервисная функция RDS rdsSetBlockVarDefValueByCur, запоминающая текущее значение переменной блока в качестве значения по умолчанию. Функция принимает два параметра: идентификатор блока, над переменной которого производится операция (BlockData->Block), и порядковый номер обрабатываемой переменной, начиная с нуля. В данном блоке три переменных: «Start» (номер 0), «Ready» (номер 1) и «Color» (номер 2), поэтому чтобы изменить значение по умолчанию у переменной Color, нужно передать в функцию число 2. Таким образом, вызов функции rdsSetBlockVarDefValueByCur с параметрами BlockData->Block и 2 делает значение переменной Color по умолчанию равным ее текущему значению, то есть цвету, только что полученному из закрытого пользователем диалога. После этого переменной result присваивается константа RDS_BFR_MODIFIED, чтобы возвращаемое функцией значение сообщило RDS о наличии изменений в схеме.

Рис. 53. Вызов модального диалога
из функции настройки блока

Чтобы проверить работу этой модели, нужно установить флаг «блок имеет функцию настройки» в окне параметров блока и, для наглядности, задать блоку векторную картинку с какой-нибудь простой геометрической фигурой (например, прямоугольником), цвет которой связан с переменной блока «Color». Теперь, если выбрать в контекстном меню блока пункт «настройка», задать в открывшемся окне диалога какой-нибудь цвет (рис. 53) и перейти из режима редактирования в режим моделирования, картинка блока должна окраситься в выбранный цвет.