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

Описания RDS

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

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

§2.12. Реакция блоков на действия пользователя

§2.12.5. Реакция окон подсистем на мышь и клавиатуру

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

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

### §2.12. Реакция блоков на действия пользователя

#### §2.12.5. Реакция окон подсистем на мышь и клавиатуру

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

Если на нажатие или отпускание кнопок мыши и перемещение ее курсора не среагировал ни один из блоков подсистемы, это событие может обработать модель самой подсистемы (если, конечно, у подсистемы есть модель). Точно так же, если была нажата или отпущена какая-либо клавиша, и ни один из блоков активной подсистемы не сообщил RDS, что это событие обработано, RDS может вызвать соответствующую реакцию модели подсистемы. Разумеется, все это возможно только в режимах моделирования и расчета – в режиме редактирования RDS не передает информацию о мыши и клавиатуре моделям блоков и подсистем. Модели подсистем не участвуют в обработке данных, передающихся по связям от блока к блоку, и не вызываются в цикле в режиме расчета, поэтому в схемах они используются не так часто. Однако, в некоторых случаях, они могут быть полезны.

В качестве примера создадим модель подсистемы, которая при щелчке правой кнопкой мыши на рабочем поле будет переключать масштаб со 100% на 400% и обратно, прокручивая при этом рабочее поле так, чтобы точка щелчка пришлась в центр окна. Кроме того, при нажатии курсорных клавиш одновременно с клавишей Shift, окно подсистемы должно перемещаться в направлении нажатой клавиши на 5 точек экрана.

В целом, модели подсистем выглядят так же, как и модели простых блоков, за исключением того, что модель подсистемы не имеет доступа к статическим переменным. Наша модель будет выглядеть следующим образом:

      // Модель подсистемы с реакцией на мышь и клавиатуру
      extern "C" __declspec(dllexport)
        int RDSCALL SystemReaction(int CallMode,
                          RDS_PBLOCKDATA BlockData,
                          LPVOID ExtParam)
      { // Вспомогательные переменные
        RDS_EDITORPARAMETERS win;
        RDS_PMOUSEDATA mouse;
        RDS_PKEYDATA key;
        int x,y;

        switch(CallMode)
          { // Нажатие кнопки мыши в окне подсистемы
            case RDS_BFM_WINDOWMOUSEDOWN:
              // Приведение ExtParam к нужному типу
              mouse=(RDS_PMOUSEDATA)ExtParam;
              if(mouse->Button!=RDS_MRIGHTBUTTON)
                break; // Не правая кнопка - выходим
              // Вычисляем координаты щелчка в масштабе 100%
              x=mouse->x/mouse->DoubleZoom;
              y=mouse->y/mouse->DoubleZoom;
              // Установка нового масштаба подсистемы
              rdsSetZoomPercent(BlockData->Block,
                                mouse->IntZoom>100?100:400,x,y);
              break;

            // Нажатие клавиши в окне подсистемы
            case RDS_BFM_WINDOWKEYDOWN:
              // Приведение ExtParam к нужному типу
              key=(RDS_PKEYDATA)ExtParam;
              // Проверяем, нажата ли Shift
              if(key->Shift!=RDS_KSHIFT)
                break; // Не нажата - выходим
              // Получаем текущее положение окна подсистемы
              win.servSize=sizeof(win);
              if(!rdsGetEditorParameters(BlockData->Block,&win))
                break;
              // Если окно свернуто или развернуто, перемещать не надо
              if(win.WinMaximized || win.WinMinimized)
                break;
              //В зависимости от нажатой клавиши, вычисляем
              // перемещение окна (x,y)
              x=y=0;
              switch(key->KeyCode)
                { case VK_LEFT:  x=-5; break; // Влево
                  case VK_RIGHT: x=5;  break; // Вправо
                  case VK_UP:    y=-5; break; // Вверх
                  case VK_DOWN:  y=5;  break; // Вниз
                }
              // Если x или y не нулевые - перемещаем окно
              if(x||y)
                rdsSetSystemWindowBounds(BlockData->Block,FALSE,
                                         win.WinLeft+x,win.WinTop+y,
                                         win.WinWidth,win.WinHeight);
              break;
          }
        return RDS_BFR_DONE;
      }
      //=========================================

Модель состоит из двух реакций: реакции на нажатие кнопки мыши в окне подсистемы RDS_BFM_WINDOWMOUSEDOWN и реакции на нажатие клавиши в окне RDS_BFM_WINDOWKEYDOWN. Они похожи на соответствующие реакции блока (RDS_BFM_MOUSEDOWN и RDS_BFM_KEYDOWN), в параметре ExtParam при их вызове передаются указатели на те же самые структуры. Нужно помнить, что подсистема тоже является блоком в родительской подсистеме, и там, как и любой блок, она тоже может реагировать на нажатие кнопок мыши и клавиш, получая обычные сообщения RDS_BFM_MOUSEDOWN и RDS_BFM_KEYDOWN (см. рис. 12).

Рассмотрим сначала реакцию на нажатие кнопки мыши. В параметре ExtParam в этом случае передается указатель на структуру описания события RDS_MOUSEDATA, который, после приведения к соответствующему типу, записывается во вспомогательную переменную mouse. Поскольку нас интересуют только щелчки правой кнопкой, нажатая кнопка сравнивается с константой RDS_MRIGHTBUTTON, и, при несовпадении, реакция завершается. Затем координаты щелчка приводятся к масштабу 100% (для этого их нужно поделить на масштабный коэффициент mouse->DoubleZoom) и вызывается сервисная функция rdsSetZoomPercent, устанавливающая новый масштаб указанной подсистемы. В первом параметре функции передается идентификатор подсистемы (в нашей модели – идентификатор данного блока, то есть BlockData->Block), во втором – устанавливаемый масштаб в процентах, в третьем и четвертом – координаты точки (указанные в масштабе 100%), которую нужно установить в центр окна. Масштаб, который мы устанавливаем, вычисляется на основе текущего масштаба в процентах mouse->IntZoom: если он больше 100, устанавливается 100%, если меньше или равен – 400%. Таким образом, вызов этой функции при масштабе 100% переключит его на 400%, а при 400% – обратно на 100%, что нам и требовалось.

Теперь рассмотрим реакцию на нажатие клавиши. В параметре ExtParam, как и в режиме RDS_BFM_KEYDOWN, передается указатель на структуру описания нажатой клавиши RDS_KEYDATA, который записывается во вспомогательную переменную key. Далее проверяется состояние флага клавиши Shift: если она не нажата, дальнейшая обработка не требуется, поскольку нажатия курсорных клавиш нас интересуют только при нажатой клавише Shift. Затем, вызывая уже знакомую нам функцию rdsGetEditorParameters, мы заполняем структуру win описанием окна подсистемы. В ней нас будут интересовать логические поля WinMaximized и WinMinimized, указывающие на то, что окно полностью развернуто или свернуто (в обоих случаях перемещать его нельзя), а также координаты левого верхнего угла окна подсистемы WinLeft и WinTop, и размеры этого окна WinWidth и WinHeight. Далее, в зависимости от нажатой курсорной клавиши, в переменных x и y формируется необходимое смещение окна на ±5 точек экрана в нужном направлении (если нажатая клавиша – не курсорная, значения x и y останутся нулевыми). Затем, если смещения не нулевые, вызывается функция установки положения и размеров окна подсистемы rdsSetSystemWindowBounds, в которую прежний левый верхний угол окна передается с вычисленными смещениями. В первом параметре этой функции передается идентификатор подсистемы, окно которой двигается, во втором – логическое значение, указывающее на необходимость развернуть окно на весь экран (в данном случае FALSE, разворачивать не нужно). Третий и четвертый параметры – новые координаты левого верхнего угла, пятый и шестой – новые ширина и высота (в нашем случае передаются старые, полученные из структуры описания окна, поскольку размер окна мы не меняем).

Чтобы проверить работу этой модели, необходимо подключить ее к какой-либо подсистеме и разрешить в параметрах этой подсистемы реакцию на необработанные блоками события мыши и клавиатуры (рис. 81).

Рис. 81. Включение реакции на клавиатуру и мышь
в параметрах подсистемы

Теперь в режимах моделирования и расчета нажатие курсорных клавиш одновременно с клавишей Shift должно перемещать окно по экрану, если это окно активно, а щелчок правой кнопкой мыши на рабочем поле окна должен менять масштаб со 100% на 400% и обратно. Разумеется, если щелкнуть правой кнопкой мыши по какому-либо блоку, которому разрешено реагировать на мышь, информацию о щелчке получит модель этого блока, и масштаб окна не изменится, поскольку модель подсистемы не будет вызвана (если только модель среагировавшего блока не вернет константу RDS_BFR_NOTPROCESSED).

Надо отметить, что для того, чтобы управлять окном подсистемы, не обязательно подключать к подсистеме модель. Функции установки масштаба и положения окна, использованные в этом примере, работают с любой подсистемой, идентификатор которой передан им в параметрах. Эти функции можно вызывать и из моделей простых блоков, указывая идентификатор родительской подсистемы. Например, можно разместить в подсистеме на заднем плане (или на самом дальнем слое) блок размером во всю рабочую область этой подсистемы, разрешить ему реакцию на мышь, и в его модели по щелчку правой кнопкой мыши менять масштаб подсистемы так же, как и в описанном примере. Таким же образом один из простых блоков может реагировать на нажатия курсорных клавиш при нажатой клавише Shift и перемещать окно родительской подсистемы. Где реализовывать те или иные функции – в модели подсистемы или в модели одного из ее блоков – разработчик решает сам, исходя из своих представлений об удобстве программирования.