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

Описания RDS

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

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

§2.10. Программное рисование внешнего вида блока

§2.10.3. Дополнительное рисование

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

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

### §2.10. Программное рисование внешнего вида блока

#### §2.10.3. Дополнительное рисование

Рассматривается рисование дополнительных элементов поверх изображения блока. В описанный ранее график добавляется рисование иконки, указывающей на отсутствие доступа к необходимой ему переменной времени.

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

Для того, чтобы модель могла нарисовать что-либо поверх изображения блока, независимо от способа, которым задан его внешний вид, в RDS введен специальный режим вызова модели для дополнительного рисования. После того, как изображение блока (будь то прямоугольник с текстом, векторная картинка или результат программного рисования) выведено в окно подсистемы, модель вызывается в режиме RDS_BFM_DRAWADDITIONAL и ей передается указатель на структуру RDS_DRAWDATA, как и в режиме RDS_BFM_DRAW. В этом дополнительном режиме модель может при помощи функций Windows API или сервисных функций RDS рисовать в окне подсистемы что угодно, как и при уже рассмотренном программном рисовании. Главное отличие режима вызова RDS_BFM_DRAWADDITIONAL от RDS_BFM_DRAW заключается в том, что в режиме RDS_BFM_DRAW модель вызывается только при включенном в параметрах блока программном рисовании (см. рис. 58), а в режиме RDS_BFM_DRAWADDITIONAL она вызывается всегда при обновлении окна подсистемы. Таким образом, включение в модель блока реакции на вызов в этом режиме позволяет делать на любом блоке произвольные пометки, на которые не будет влиять даже изменение внешнего вида блока пользователем. Модель, которой не нужно ничего рисовать поверх изображения блока, может просто игнорировать этот вызов.

Для иллюстрации дополнительного рисования снова возьмем блок-график, рассмотренный в §2.10.1 и §2.10.2. Для построения графика зависимости своего входа от времени этот блок использует стандартную динамическую переменную «DynTime», из которой он берет текущее значение времени. Создать эту переменную и присваивать ей значения должен другой блок (например, стандартный планировщик динамического расчета из библиотеки блоков RDS), без нее график строиться не будет, и на экран будут выведены только координатные оси с числами. Было бы правильно в этом случае привлечь внимание пользователя к графику, нарисовав на нем иконку, сигнализирующую о неработоспособности блока. Стандартные библиотечные блоки в этом случае рисуют красный восклицательный знак в круге на желтом поле, мы поступим так же.

Прежде всего, введем в класс личной области данных блока новую функцию-член DrawAdditional, которая будет выводить указанную иконку при отсутствии доступа к переменной «DynTime». Эта функция, как и две других функции рисования, уже имеющиеся в классе, будет принимать единственный параметр – указатель на структуру RDS_DRAWDATA, полученный моделью блока из RDS при ее вызове в режиме RDS_BFM_DRAWADDITIONAL (добавленная функция выделена цветом):

      //=========================================
      // Простой график – личная область данных
      //=========================================
      class TSimplePlotData
      {
          // …

          void LoadText(char *text);	// Функция загрузки параметров
          void Draw(RDS_PDRAWDATA DrawData); // Функция рисования
          // Функция быстрого рисования
          void DrawFast(RDS_PDRAWDATA DrawData);
          // Рисование иконки при отсутствии доступа к DynTime
          void DrawAdditional(RDS_PDRAWDATA DrawData);
          // …
          // … далее без изменений …

Для вызова DrawAdditional из функции модели блока, в оператор switch нужно вставить новую метку case:

          // Рисование внешнего вида блока
          case RDS_BFM_DRAW:
            // data->Draw((RDS_PDRAWDATA)ExtParam);
            data->DrawFast((RDS_PDRAWDATA)ExtParam);
            break;

          // Дополнительное рисование
          case RDS_BFM_DRAWADDITIONAL:
            data->DrawAdditional((RDS_PDRAWDATA)ExtParam);
            break;

Теперь напишем функцию DrawAdditional. Она должна проверять, есть ли у блока доступ к переменной «DynTime» (необходимо проверить поле класса Time, в котором должен храниться указатель на структуру подписки), и, при отсутствии доступа, нарисовать иконку. Красный восклицательный знак в желтом круге – одна из стандартных иконок RDS, поэтому для ее рисования мы будем использовать сервисную функцию.

      // Дополнительное рисование
      void TSimplePlotData::DrawAdditional(RDS_PDRAWDATA DrawData)
      {
        // Проверка доступа к переменной времени
        if(Time==NULL || Time->Data==NULL)	// Доступа нет
          { int w,h;
            // Константа, указывающая на стандартную иконку RDS
            DWORD icon=RDS_STDICON_YELCIRCEXCLAM;
            // Определяем размер иконки и выводим ее в центре блока
            if(rdsXGGetStdIconSize(icon,&w,&h))
              rdsXGDrawStdIcon(DrawData->Left+(DrawData->Width-w)/2,
                               DrawData->Top+(DrawData->Height-h)/2,
                               icon);
          }
      }
      //=========================================

Прежде всего в этой функции проверяется наличие доступа к динамической переменной, на которую ссылается указатель на структуру подписки Time, и все дальнейшие действия производятся только при отсутствии этого доступа. Чтобы нарисовать иконку в центре изображения блока, где она с большей вероятностью привлечет внимание пользователя, необходимо сначала определить размеры этой иконки. Каждой стандартной иконке RDS соответствует целая константа RDS_STDICON_*, используемая в сервисных функциях. Красному восклицательному знаку в желтом круге соответствует константа RDS_STDICON_YELCIRCEXCLAM. Для улучшения читаемости программы эта константа присваивается вспомогательной переменной icon. Затем вызывается сервисная функция rdsXGGetStdIconSize, которая определяет ширину и высоту указанной иконки и помещает их в переменные w и h соответственно. Поскольку мы используем стандартную иконку RDS, можно было бы не определять ее размеры – известно, что ее ширина и высота равны 16 точкам. Однако, при дальнейшей модернизации RDS эти размеры могут быть изменены, поэтому лучше получить их текущее значение при помощи сервисной функции. Зная размеры иконки и координаты прямоугольника блока, которые можно взять из структуры DrawData, можно вывести эту иконку в центр прямоугольника вызовом сервисной функции rdsXGDrawStdIcon. Первые два параметра функции – горизонтальная и вертикальная координаты верхнего левого угла выводимой иконки, третий – уникальный идентификатор стандартной иконки RDS (в нашем случае – RDS_STDICON_YELCIRCEXCLAM).

Теперь, если удалить из схемы планировщик динамических вычислений, в центре графика немедленно появится иконка, сигнализирующая об ошибке (рис. 64). Если вернуть планировщик обратно, иконка немедленно исчезнет. Это позволит пользователю, посмотрев на схему, сразу определить неправильно работающие блоки. На самом деле, кроме иконки, указывающей на наличие ошибки, было бы неплохо информировать пользователя о самой ошибке (в данном случае, указывать на отсутствие в системе переменной времени). Можно было бы вывести на изображении блока какой-либо описывающий ошибку текст, но в мелких масштабах он будет нечитаемым и ничем не поможет пользователю. Такие поясняющие тексты лучше всего выводить во всплывающих подсказках, которые рассмотрены в §2.11.

Рис. 64. Внешний вид графика без доступа к динамической переменной