Навигация:
<< >> Оглавление Указатель
Текст С++

Полный исходный текст на языке C++ для библиотеки (DLL) с моделями блоков, иллюстрирующих прямой вызов функции одного блока. Библиотека содержит две модели:

Изменения относительно предыдущих версий этих моделей выделены цветом.

  // Прямой вызов функции блока
  #include <windows.h>
  #include <RdsDef.h>
  // Подготовка описаний сервисных функций
  
  #include <RdsFunc.h>

  //==========  ==========
  int WINAPI ( /*hinst*/,
                           unsigned long reason,
                           void* /*lpReserved*/)
  { if(reason==DLL_PROCESS_ATTACH) // Загрузка DLL
      { // Получение доступа к функциям RDS
        if(!GetInterfaceFunctions())
           // Сообщение: старая версия RDS
      }
    return 1;
  }
  //========= Конец главной функции =========

// Глобальная переменная для уникального идентификатора функции // "Common.ControlValueChanged" int ControlValueChangedId=0;
// Функция обратного вызова для "Common.ControlValueChanged" ControlValChanged_Callback( /*src*/, dest, /*data*/) { // Вызов функции "Common.ControlValueChanged" у блока на другом // конце связи (dest->Block,ControlValueChangedId,NULL); // Возвращаем TRUE – не останавливаем перебор блоков return TRUE; } //=========================================
// Функция уведомления соседей об изменении значения void ControlValueChangedCall( *pCancelCall) { // В параметре pCancelCall передается указатель на флаг // блокировки вызова функции if(*pCancelCall) // Вызов заблокирован return; // Принудительно передаем данные выходов блока, модель которого // сейчас выполняется, по связям (NULL,TRUE); // Взводим флаг блокировки перед вызовом функций *pCancelCall=TRUE; // Перебираем все простые блоки, соединенные с выходами текущего // (для каждого будет вызвана ControlValChanged_Callback) (NULL, | , ControlValChanged_Callback, NULL); // Сбрасываем флаг блокировки после вызова функций *pCancelCall=FALSE; } //=========================================
//==================================================================== // Уменьшающий/увеличивающий выход блок //==================================================================== //====== Класс личной области данных ====== class TPlusMinusData { public: int KeyPlus; // Клавиша увеличения ShiftsPlus; // и ее флаги int KeyMinus; // Клавиша уменьшения ShiftsMinus; // и ее флаги
// Флаг блокировки повторных вызовов // функции "Common.ControlValueChanged" NoCall;
int Setup(void); // Функция настройки клавиш void SaveBin(void); // Сохранение параметров int LoadBin(void); // Загрузка параметров // Конструктор класса TPlusMinusData(void) { KeyPlus=ShiftsPlus=KeyMinus=ShiftsMinus=0;
NoCall=FALSE; // Исходно флаг блокировки сброшен if(ControlValueChangedId==0) // Регистрация функции ControlValueChangedId= ("Common.ControlValueChanged");
}; }; //========================================= // Функция задания клавиш // // // int TPlusMinusData::Setup(void) { window; // Идентификатор вспомогательного объекта ok; // Пользователь нажал "OK" // Создание окна window=(FALSE,-1,-1,"Плюс/минус"); // Добавление полей ввода (window,0,1,, "Клавиша увеличения:",80); (window,0,2,, "Клавиша уменьшения:",80); // Занесение исходных значений кодов клавиш в поля ввода (window,1,,KeyPlus); (window,1,,ShiftsPlus); (window,2,,KeyMinus); (window,2,,ShiftsMinus); // Открытие окна ok=(window,NULL); if(ok) { // Нажата кнопка OK - запись кодов клавиш в класс KeyPlus=(window,1,); ShiftsPlus=(window,1,); KeyMinus=(window,2,); ShiftsMinus=(window,2,); } // Уничтожение окна (window); // Возвращаемое значение return ok?:; } //========================================= // Сохранение параметров void TPlusMinusData::SaveBin(void) { tag; // Переменная для байта тега tag=1; // Тег 1 - клавиша увеличения (&tag,sizeof(tag)); (&KeyPlus,sizeof(KeyPlus)); (&ShiftsPlus,sizeof(ShiftsPlus)); tag=2; // Тег 2 - клавиша уменьшения (&tag,sizeof(tag)); (&KeyMinus,sizeof(KeyMinus)); (&ShiftsMinus,sizeof(ShiftsMinus)); tag=0; // Тег 0 - конец данных (&tag,sizeof(tag)); } //========================================= // Загрузка параметров int TPlusMinusData::LoadBin(void) { tag; for(;;) // Цикл до тех пор, пока данные не кончатся { // Читаем байт тега if(!(&tag,sizeof(tag))) break; // Тег не считан - данные кончились // Анализируем считанный тег switch(tag) { case 0: // Конец данных блока return ; // Загрузка успешно завершена case 1: // Данные клавиши увеличения (&KeyPlus,sizeof(KeyPlus)); (&ShiftsPlus,sizeof(ShiftsPlus)); break; case 2: // Данные клавиши уменьшения (&KeyMinus,sizeof(KeyMinus)); (&ShiftsMinus,sizeof(ShiftsMinus)); break; default: // Неопознанный тег return RDS_BFR_ERROR; // Сообщаем RDS об ошибке } } // Данные кончились до тега 0 - сообщаем об ошибке return RDS_BFR_ERROR; } //========================================= // Увеличение/уменьшение значения по щелчку и клавишам extern "C" __declspec(dllexport) int PlusMinus(int CallMode, BlockData, ExtParam) { // #define pStart ((char *)(BlockData->VarTreeData)) #define Start (*((char *)(pStart))) #define Ready (*((char *)(pStart+RDS_VSZ_S))) #define v (*((RDSINT32 *)(pStart+2*RDS_VSZ_S))) #define input (*((RDSINT32 *)(pStart+2*RDS_VSZ_S+RDS_VSZ_I))) // Вспомогательная — указатель на структуру события мыши mouse; // Вспомогательная — указатель на структуру события клавиатуры key; // Указатель на личную область данных блока,приведенный к // правильному типу TPlusMinusData *data=(TPlusMinusData*)(BlockData->BlockData); switch(CallMode) { // Проверка типа статических переменных case : return strcmp((char*)ExtParam,"{SSII}")? :; // Реакция на нажатие кнопки мыши case : // Приведение ExtParam к нужному типу mouse=()ExtParam; if(mouse->Button==) { // Нажата левая кнопка // Проверяем, есть ли у блока картинка (получаем описание блока) descr; descr.servSize=sizeof(descr); (BlockData->Block,&descr); if(descr.Flags & ) { // Картинка есть – определяем идентификатор // элемента под курсором int id=(mouse); v+=id; } else if(mouse->y<mouse->Top+mouse->Height/2) v++; // В верхней половине блока - увеличиваем else v--; // В нижней половине блока — уменьшаем // Взводим сигнал готовности Ready=1;
// Принудительно передаем в соседние блоки ControlValueChangedCall(&(data->NoCall));
} break; case : // Инициализация BlockData->BlockData=new TPlusMinusData(); break; case :// Очистка данных delete data; break; case : // Настройка параметров return data->Setup(); case :// Сохранение параметров data->SaveBin(); break; case :// Загрузка параметров return data->LoadBin(); // Реакция на нажатие клавиши case : // Приведение ExtParam к нужному типу key=()ExtParam; // Сравнение нажатой клавиши с клавишами уменьшения // и увеличения if(key->KeyCode==data->KeyPlus && key->Shift==data->ShiftsPlus) { v++; Ready=1; } else if(key->KeyCode==data->KeyMinus && key->Shift==data->ShiftsMinus) { v--; Ready=1; }
// Принудительно передаем в соседние блоки if(Ready) ControlValueChangedCall(&(data->NoCall));
break;
// Такт расчета case : if(v==input) // Новое значение равно старому { Ready=0; // Не передаем по связям break; } v=input; // Передаем значение входа на выход // Принудительно передаем в соседние блоки ControlValueChangedCall(&(data->NoCall)); break;
// Реакция на вызов функции блока case : if((()ExtParam)->Function== ControlValueChangedId) { // Вызвана"Common.ControlValueChanged" if(data->NoCall) // Взведен флаг блокировки break; if(v==input) // Новое значение равно старому - break; // передавать не нужно v=input; // Передаем значение входа на выход Ready=1; // Взводим сигнал готовности // Принудительно передаем в соседние блоки ControlValueChangedCall(&(data->NoCall)); } break;
} return ; // Отмена макроопределений #undef input #undef v #undef Ready #undef Start #undef pStart } //========================================= //============================================================================ // Двухкоординатная рукоятка //============================================================================ //====== Класс личной области данных ====== class TSimpleJoystick { private: // Центр круга (рукоятки) до начала перетаскивания int OldHandleX,OldHandleY; // Координаты курсора на момент начала перетаскивания int OldMouseX,OldMouseY; // Флаги фиксации одной из координат LockX,LockY; // Идентификаторы добавленных пунктов меню MenuLockX,MenuLockY; public: // Настроечные параметры блока BorderColor; // Цвет рамки блока FieldColor; // Цвет прямоугольника HandleColor; // Цвет круга в покое MovingHandleColor; // Цвет круга при таскании GrayedColor; // Цвет недоступной области int HandleSize; // Диаметр круга
// Флаг блокировки повторных вызовов // функции "Common.ControlValueChanged" NoCall;
// Реакция на нажатие кнопки мыши int MouseDown( mouse,double x,double y, *pFlags); // Реакция на перемещение курсора мыши void MouseMove( mouse,double *px,double *py); // Рисование изображения блока void Draw( draw,double x,double y, moving); // Реакция на выбор добавленного пункта меню void MenuFunction( MenuData); // Реакция на изменение размеров блока void Resizing( ResData);
// Ограничение входных значений void LimitInputValues(double *px_in,double *py_in,double x,double y);
// Конструктор класса TSimpleJoystick(void) { BorderColor=0; // Черная рамка FieldColor=0xffffff; // Белое поле HandleColor=0xff0000; // Синий круг MovingHandleColor=0xff; // Красный при таскании HandleSize=20; // Диаметр круга GrayedColor=0x7f7f7f; // Серый LockX=LockY=FALSE; // Фиксация выключена // Создание пунктов меню // // // MenuLockX=("Фиксировать X",1,0); MenuLockY=("Фиксировать Y",2,0);
NoCall=FALSE; // Исходно флаг блокировки сброшен if(ControlValueChangedId==0) // Регистрация функции ControlValueChangedId= ("Common.ControlValueChanged");
}; // Деструктор класса ~TSimpleJoystick() { // Уничтожение пунктов меню (MenuLockX); (MenuLockY); }; }; //========================================= // Рисование изображения блока void TSimpleJoystick::Draw( draw, double x,double y,BOOL moving) { int hx,hy,cx,cy; r; int hR=HandleSize*draw->DoubleZoom/2; // Радиус круга-рукоятки // Если размер блока - нулевой, рисовать негде if(draw->Height==0 || draw->Width==0) return; // Рисование поля блока (0,,1,BorderColor,); (0,,FieldColor); (draw->Left,draw->Top, draw->Left+draw->Width,draw->Top+draw->Height); // Вычисление центра прямоугольника блока cx=draw->Left+draw->Width/2; cy=draw->Top+draw->Height/2; // Вычисление координат центра круга-рукоятки hx=cx+x*draw->Width/2; hy=cy-y*draw->Height/2; // Установка области отсечения r.left=draw->Left+1; r.top=draw->Top+1; r.right=draw->Left+draw->Width-1; r.bottom=draw->Top+draw->Height-1; (&r); // Рисование ограничений if(LockX||LockY) // Фиксируется одна из координат { // Установка серого цвета заливки (0,,GrayedColor); if(LockX) // Фиксируется X { (r.left,r.top,hx-hR,r.bottom); // Слева (hx+hR,r.top,r.right,r.bottom);// Справа } else // Фиксируется Y { (r.left,r.top,r.right,hy-hR); // Сверху (r.left,hy+hR,r.right,r.bottom);// Снизу } } // Линии перекрестия (cx,draw->Top); (cx,draw->Top+draw->Height); (draw->Left,cy); (draw->Left+draw->Width,cy); // Рисование круга (цвет зависит от параметра moving) (,,0,0,0); (0,, moving?MovingHandleColor:HandleColor); (hx-hR,hy-hR,hx+hR+1,hy+hR+1); // Отмена отсечения (NULL); } //========================================= // Реакция на нажатие кнопки мыши int TSimpleJoystick::MouseDown( mouse, double x,double y,DWORD *pFlags) { int hx,hy,cx,cy, hR=HandleSize*mouse->DoubleZoom/2; // Радиус круга // Если размер - нулевой, реакция не имеет смысла if(mouse->Height==0 || mouse->Width==0) return RDS_BFR_DONE; // Если нажата не левая кнопка, перетаскивать не надо // Разрешаем в этом случае вызов контекстного меню блока if(mouse->Button!=) return ; // Координаты цента блока cx=mouse->Left+mouse->Width/2; cy=mouse->Top+mouse->Height/2; // Координаты центра круга-рукоятки hx=cx+x*mouse->Width/2; hy=cy-y*mouse->Height/2; // Проверка попадания курсора в круг if(abs(mouse->x-hx)<=hR && abs(mouse->y-hy)<=hR) { // Курсор попал в круг // Запоминаем координаты центр круга на момент // начала перетаскивания OldHandleX=hx; OldHandleY=hy; // Координаты курсора на начало перетаскивания OldMouseX=mouse->x; OldMouseY=mouse->y; // Взводим флаг захвата мыши *pFlags|=; } // Курсор не попал в рукоятку - захватывать мышь // и подготавливать перетаскивание не нужно return ; } //========================================= // Реакция на перемещение курсора мыши void TSimpleJoystick::MouseMove( mouse, double *px,double *py) { int hx,hy,cx,cy; // Если размер - нулевой, реакция не имеет смысла if(mouse->Height==0 || mouse->Width==0) { *px=*py=0.0; return; } // Новые координаты центра рукоятки hx=OldHandleX+(mouse->x-OldMouseX); hy=OldHandleY+(mouse->y-OldMouseY); // Координаты центра блока cx=mouse->Left+mouse->Width/2; cy=mouse->Top+mouse->Height/2; // По новым координатам центра рукоятки вычисляем соответствующие // им вещественные значения выходов, ограничивая их // диапазоном [-1...1] if(!LockX) { *px=2.0*(hx-cx)/mouse->Width; if(*px>1.0) *px=1.0; else if(*px<-1.0) *px=-1.0; } if(!LockY) { *py=-2.0*(hy-cy)/mouse->Height; if(*py>1.0) *py=1.0; else if(*py<-1.0) *py=-1.0; } } //========================================= // Функция реакции на выбор одного из пунктов меню void TSimpleJoystick::MenuFunction( MenuData) { switch(MenuData->Function) { case 1: // Выбран пункт "Фиксировать X" LockX=!LockX; // Переключаем флаг фиксации X LockY=FALSE; // Отключаем фиксацию Y break; case 2: // Выбран пункт "Фиксировать Y" LockY=!LockY; // Переключаем флаг фиксации Y LockX=FALSE; // Отключаем фиксацию X break; } // Установка галочек у пунктов меню в зависимости от // флагов фиксации координат (MenuLockX,LockX?:0); (MenuLockY,LockY?:0); } //========================================= // Реакция на изменение размеров блока void TSimpleJoystick::Resizing( ResData) { if(ResData->HorzResize && (!ResData->VertResize)) // Перетаскивается левый или правый маркер ResData->newHeight=ResData->newWidth; else if((!ResData->HorzResize) && ResData->VertResize) // Перетаскивается верхний или нижний маркер ResData->newWidth=ResData->newHeight; else // Перетаскивается угловой маркер или размер задан точно { // Вычисляем среднее арифметическое int avg=(ResData->newWidth+ResData->newHeight)/2; // Присваиваем его ширине и высоте ResData->newWidth=ResData->newHeight=avg; } } //========================================= // Ограничение значений входов блока void TSimpleJoystick::LimitInputValues(double *px_in,double *py_in, double x,double y) { // px_in, py_in - указатели на входы блока // x, y - текущие значения выходов if(LockX) // Координата x зафиксирована *px_in=x; // Присваиваем входу x_in зафиксированное значение else // Ограничиваем x_in диапазоном [-1...1] { if(*px_in<-1.0) *px_in=-1.0; else if(*px_in>1.0) *px_in=1.0; } if(LockY) // Координата y зафиксирована *py_in=y; // Присваиваем входу y_in зафиксированное значение else // Ограничиваем y_in диапазоном [-1...1] { if(*py_in<-1.0) *py_in=-1.0; else if(*py_in>1.0) *py_in=1.0; } } //========================================= // Функция модели блока extern "C" __declspec(dllexport) int E SimpleJoystick(int CallMode, BlockData, ExtParam) { // #define pStart ((char *)(BlockData->VarTreeData)) #define Start (*((char *)(pStart))) #define Ready (*((char *)(pStart+RDS_VSZ_S))) #define x (*((double *)(pStart+2*RDS_VSZ_S))) #define y (*((double *)(pStart+2*RDS_VSZ_S+RDS_VSZ_D))) #define x_in (*((double *)(pStart+2*RDS_VSZ_S+2*RDS_VSZ_D))) #define y_in (*((double *)(pStart+2*RDS_VSZ_S+3*RDS_VSZ_D))) #define x_in_ok (*((char *)(pStart+2*RDS_VSZ_S+4*RDS_VSZ_D))) #define y_in_ok (*((char *)(pStart+3*RDS_VSZ_S+4*RDS_VSZ_D))) // Вспомогательная переменная - указатель на личную область, // приведенный к правильному типу TSimpleJoystick *data=(TSimpleJoystick*)(BlockData->BlockData); switch(CallMode) { // Инициализация case : BlockData->BlockData=new TSimpleJoystick(); break; // Очистка case : delete data; break; // Проверка допустимости типов переменных case : return strcmp((char*)ExtParam,"{SSDDDDSS}")? :; // Нажатие кнопки мыши case : return data->MouseDown(()ExtParam,x,y, &(BlockData->Flags)); // Отпускание кнопки мыши case : // Снятие захвата мыши (BlockData->Flags,,FALSE); break; // Перемещение курсора мыши case : // Проверка: включен ли захват мыши if(BlockData->Flags & ) // Включен { // Запоминаем старые значения double oldX=x,oldY=y; // Вызываем функцию реакции data->MouseMove(()ExtParam,&x,&y); Ready=1; // Взводим сигнал готовности // Если значения изменились, передаем соседям if(oldX!=x || oldY!=y) ControlValueChangedCall(&(data->NoCall)); } break; // Рисование case : data->Draw(()ExtParam,x,y, BlockData->Flags & ); break; // Выбор пользователем добавленного пункта меню case : data->MenuFunction(()ExtParam); break; // Изменение размеров блока case : case : data->Resizing(()ExtParam); break;
// Один такт расчета case : if(x_in_ok==0 && y_in_ok==0) { // Связанные сигналы не взведены Ready=0; // Сбрасываем сигнал готовности break; } if(x==x_in && y==y_in) { // На входах те же значения, что и на выходах Ready=x_in_ok=y_in_ok=0; // Сбрасываем все сигналы break; } // Ограничиваем входные значения data->LimitInputValues(&x_in,&y_in,x,y); // В зависимости от того, какой связанный сигнал взведен, // копируем соответствующие входы в выходы if(x_in_ok) x=x_in; if(y_in_ok) y=y_in; x_in_ok=y_in_ok=0; // Сбрасываем связанные сигналы // Передаем данные соединенным блокам ControlValueChangedCall(&(data->NoCall)); break;
// Реакция на вызов функции case : if((()ExtParam)->Function== ControlValueChangedId) { // Вызвана "Common.ControlValueChanged" if(data->NoCall) // Вызов заблокирован break; // Ограничиваем входные значения data->LimitInputValues(&x_in,&y_in,x,y); // Если связанные сигналы не взведены - не реагируем if(x_in_ok==0 && y_in_ok==0) break; // Если значения входов те же, что и у выходов - // не реагируем if(x_in==x && y_in==y) break; // Копируем входы в выходы согласно связанным сигналам if(x_in_ok) x=x_in; if(y_in_ok) y=y_in; x_in_ok=y_in_ok=0; // Сбрасываем связанные сигналы Ready=1; // Взводим сигнал готовности // Передаем данные соединенным блокам ControlValueChangedCall(&(data->NoCall)); } break;
} return ; // Отмена макроопределений #undef y_in_ok #undef x_in_ok #undef y_in #undef x_in #undef y #undef x #undef Ready #undef Start #undef pStart } //=========================================


<< >> Оглавление Указатель