Полный исходный текст на языке C++ для библиотеки (DLL) с моделями блоков-графиков с ускоренным рисованием. Библиотека содержит две модели:
- SimplePlot_a – вычисления координат выполняются только при изменении масштаба или шрифта чисел (изменения относительно примера из §2.10.1 выделены цветом);
- SimplePlot – перерисовываются только изменения с момента последнего рисования (изменения относительно модели SimplePlot_a выделены цветом).
// Программное рисование - оптимизация рисования графика #include <windows.h> #include <stdio.h> #include <RdsDef.h> // Подготовка описаний сервисных функций #define RDS_SERV_FUNC_BODY GetInterfaceFunctions #include <RdsFunc.h> //========== Главная функция DLL ========== int WINAPI DllMain(HINSTANCE /*hinst*/, unsigned long reason, void* /*lpReserved*/) { if(reason==DLL_PROCESS_ATTACH) // Загрузка DLL { // Получение доступа к функциям RDS if(!GetInterfaceFunctions()) RDS_SERV_ERROR_MSGW // Сообщение: старая версия RDS } return 1; } //========= Конец главной функции ========= //======================================================================= // Первый вариант оптимизации - вычисления координат выполняются // только при изменении масштаба или шрифта чисел //======================================================================= //========================================= // Простой график – личная область данных //========================================= class TSimplePlotData_a { private:// Запомненные координаты поля графика int Gr_x1,Gr_x2,Gr_y1,Gr_y2; // Масштаб окна на момент последнего рисования double OldZoom;// Настроечные параметры графика (цвета, шаг и т.п.) double TimeStep; // Шаг записи отсчетов RDS_SERVFONTPARAMS Font; // Шрифт чисел на осях COLORREF BorderColor; // Цвет рамки вокруг блока COLORREF FillColor; // Цвет фона блока COLORREF PlotBorderColor;// Цвет рамки поля графика COLORREF PlotFillColor; // Цвет фона поля графика COLORREF LineColor; // Цвет лини графика int LineWidth; // Толщина линии графика // Ось X double Xmin,Xmax; // Диапазон double XGridStep; // Шаг чисел на осях int XNumDecimal; // Дробная часть чисел на осях // Ось Y double Ymin,Ymax; // Диапазон double YGridStep; // Шаг чисел на осях int YNumDecimal; // Дробная часть чисел на осях // Массивы для хранения отсчетов графика double *Times; // Массив отсчетов времени double *Values; // Массив значений int Count; // Размер массивов int NextIndex; // Индекс для записи следующего значения double NextTime; // Время записи следующего значения RDS_PDYNVARLINK Time; // Связь с динамической переменной // времени ("DynTime") public:// Функция сброса запомненного масштаба последнего рисования void ResetCoords(void){OldZoom=-1.0;};// Функция отведения массивов отсчетов void AllocateArrays(void); // Функция освобождения массивов отсчетов void ClearArrays(void); // Добавление очередной точки в массив отсчетов графика void AddPoint(double v); int Setup(void); // Функция настройки параметров void SaveText(void); // Функция сохранения параметров void LoadText(char *text); // Функция загрузки параметров void Draw(RDS_PDRAWDATA DrawData); // Функция рисования TSimplePlotData_a(void); // Конструктор класса ~TSimplePlotData_a(); // Деструктор класса }; //========================================= // Модель блока extern "C" __declspec(dllexport) int RDSCALL SimplePlot_a( int CallMode, RDS_PBLOCKDATA BlockData, LPVOID 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))) // Указатель на личную область, приведенный к правильному типу TSimplePlotData_a *data=(TSimplePlotData_a*)(BlockData->BlockData); switch(CallMode) { // Инициализация блока case RDS_BFM_INIT: BlockData->BlockData=new TSimplePlotData_a(); break; // Очистка данных блока case RDS_BFM_CLEANUP: delete data; break; // Проверка типов статических переменных case RDS_BFM_VARCHECK: if(strcmp((char*)ExtParam,"{SSD}")==0) return RDS_BFR_DONE; return RDS_BFR_BADVARSMSG; // Функция настройки параметров case RDS_BFM_SETUP: data->ResetCoords(); // Сброс запомненных значений return data->Setup(); // Загрузка параметров в текстовом формате case RDS_BFM_LOADTXT: data->LoadText((char*)ExtParam); data->ResetCoords(); // Сброс запомненных значений break; // Созранение параметров в текстовом формате case RDS_BFM_SAVETXT: data->SaveText(); break;// Изменение размеров блока case RDS_BFM_RESIZE: data->ResetCoords(); // Сброс запомненных значений break;// Рисование внешнего вида блока case RDS_BFM_DRAW: data->Draw((RDS_PDRAWDATA)ExtParam); break; // Запуск расчета case RDS_BFM_STARTCALC: if(((RDS_PSTARTSTOPDATA)ExtParam)->FirstStart) data->AllocateArrays(); // Первый запуск break; // Сброс расчета case RDS_BFM_RESETCALC: data->ClearArrays(); break; // Реакция на изменение динамической переменной case RDS_BFM_DYNVARCHANGE: data->AddPoint(x); break; } return RDS_BFR_DONE; // Отмена макроопределений для переменных #undef x #undef Ready #undef Start #undef pStart } //========================================= // Конструктор класса личной области данных графика TSimplePlotData_a::TSimplePlotData_a(void) {// Инициализация OldZoom: значение -1 приведет к принудительному // вычислению Gr_x1,Gr_x2,Gr_y1 и Gr_y2 в ближайшем вызове // функции Draw OldZoom=-1.0;// Присвоение начальных значений параметрам TimeStep=0.1; // Шаг записи BorderColor=0; // Цвет рамки вокруг блока FillColor=0xffffff; // Цвет фона блока PlotBorderColor=0; // Цвет рамки окна графика и сетки PlotFillColor=0xffffff; // Цвет окна графика LineColor=0; // Цвет линии графика LineWidth=1; // Толщина линии графика // Параметры шрифта Font.servSize=sizeof(Font); strcpy(Font.Name,"Arial"); Font.SizePriority=FALSE; Font.Height=15; Font.Color=0; Font.Bold=Font.Italic=Font.Underline=Font.StrikeOut=FALSE; Font.CharSet=DEFAULT_CHARSET; // Диапазоны осей, шаг сетки, число десятичных знаков // в числах на осях Xmin=0.0; Xmax=10.0; XGridStep=5.0; XNumDecimal=0; Ymin=-1.0; Ymax=1.0; YGridStep=0.5; YNumDecimal=1; // Обнуление указателей на массивы и их размера // (массивы еще не отведены) Times=Values=NULL; Count=NextIndex=0; NextTime=Xmin; // Подписка на динамическую переменную времени Time=rdsSubscribeToDynamicVar( RDS_DVPARENT, // В родительской подсистеме "DynTime", // Имя переменной "D", // Тип переменной (double) TRUE); // Искать по иерархии } //========================================= // Деструктор класса TSimplePlotData_a::~TSimplePlotData_a() { rdsUnsubscribeFromDynamicVar(Time); // Прекратить подписку ClearArrays(); // Освободить массивы } //========================================= // Рисование внешнего вида блока void TSimplePlotData_a::Draw(RDS_PDRAWDATA DrawData) { // Вспомогательные переменные// int Gr_x1,Gr_x2,Gr_y1,Gr_y2; - эти переменные стали полями классаint x1,y1,x2,y2,textheight,w1,w2; char buf[80]; // Рамка графика rdsXGSetPenStyle(0,PS_SOLID,1,BorderColor,R2_COPYPEN); rdsXGSetBrushStyle(0,RDS_GFS_SOLID,FillColor); rdsXGRectangle(DrawData->Left,DrawData->Top, DrawData->Left+DrawData->Width, DrawData->Top+DrawData->Height); // Необходимо вычислить координаты поля графика относительно // верхнего левого угла блока // Установка параметров шрифта с учетом масштаба rdsXGSetFontByParStr(&Font,DrawData->DoubleZoom); rdsXGGetTextSize("0",NULL,&textheight); if(DrawData->DoubleZoom!=OldZoom) // Масштаб изменен { // Зазор сверху – половина высоты цифры + 1 точка Gr_y1=textheight/2+1; // Зазор снизу – полная высота цифры + 1 точка Gr_y2=DrawData->Height-textheight-1; // Зазор слева – ширина самого длинного числа вертикальной // оси или половина ширины Xmin sprintf(buf," %.*lf ",YNumDecimal,Ymin); rdsXGGetTextSize(buf,&w1,NULL); // Ширина Ymin sprintf(buf," %.*lf ",YNumDecimal,Ymax); rdsXGGetTextSize(buf,&w2,NULL); // Ширина Ymax if(w2>w1) w1=w2; sprintf(buf," %.*lf ",XNumDecimal,Xmin); rdsXGGetTextSize(buf,&w2,NULL); // Ширина Xmin w2/=2; if(w2>w1) w1=w2; Gr_x1=w1; // Зазор справа – половина ширины Xmax sprintf(buf," %.*lf ",XNumDecimal,Xmax); rdsXGGetTextSize(buf,&w2,NULL); // Ширина Xmax w2/=2; Gr_x2=DrawData->Width-w2; // Запоминание нового масштаба OldZoom=DrawData->DoubleZoom; } // if(DrawData->DoubleZoom!=OldZoom) // Абсолютные (на рабочем поле) координаты поля графика x1=DrawData->Left+Gr_x1; x2=DrawData->Left+Gr_x2; y1=DrawData->Top+Gr_y1; y2=DrawData->Top+Gr_y2; if(x1>=x2 || y1>=y2) // Негде рисовать return; // Прямоугольник поля графика rdsXGSetPenStyle(0,PS_SOLID,1,PlotBorderColor,R2_COPYPEN); rdsXGSetBrushStyle(0,RDS_GFS_SOLID,PlotFillColor); rdsXGRectangle(x1,y1,x2,y2); // Установка пунктирного стиля линии rdsXGSetPenStyle(0,PS_DOT,1,PlotBorderColor,R2_COPYPEN); rdsXGSetBrushStyle(0,RDS_GFS_EMPTY,0); // Без заливки // Горизонтальная ось с сеткой for(double x=Xmin;x<=Xmax+XGridStep*0.5;x+=XGridStep) { // ix - координата линии на рабочем поле int ix=x1+(x-Xmin)*(x2-x1)/(Xmax-Xmin); if(ix>x1 && ix<x2) // Чертим вертикальную линию { rdsXGMoveTo(ix,y1); rdsXGLineTo(ix,y2); } // Вывод числа на оси под полем sprintf(buf,"%.*lf",XNumDecimal,x); rdsXGGetTextSize(buf,&w1,NULL); rdsXGTextOut(ix-w1/2,y2,buf); } // Вертикальная ось с сеткой for(double y=Ymin;y<=Ymax+YGridStep*0.5;y+=YGridStep) { // iy - координата линии на рабочем поле int iy=y2-(y-Ymin)*(y2-y1)/(Ymax-Ymin); if(iy>y1 && iy<y2) // Чертим горизонтальную линию { rdsXGMoveTo(x1,iy); rdsXGLineTo(x2,iy); } // Вывод числа на оси слева от поля sprintf(buf,"%.*lf ",YNumDecimal,y); rdsXGGetTextSize(buf,&w1,&textheight); rdsXGTextOut(x1-w1-2,iy-textheight/2,buf); } // Если массивы не пустые – рисовать график if(Count) { RECT r; // Установить область отсечения рисования по полю графика r.left=x1+1; r.top=y1+1; r.right=x2-1; r.bottom=y2-1; rdsXGSetClipRect(&r); // Установить сплошной стиль линии, заданный для // графика цвет и толщину линии с учетом масштаба rdsXGSetPenStyle(0,PS_SOLID, LineWidth*DrawData->DoubleZoom, LineColor,R2_COPYPEN); // Строим ломанную линию по отсчетам из массивов for(int i=0;i<NextIndex;i++) { // Преобразуем вещественные отсчеты в целочисленные // координаты на рабочем поле int ix=x1+(Times[i]-Xmin)*(x2-x1)/(Xmax-Xmin), iy=y2-(Values[i]-Ymin)*(y2-y1)/(Ymax-Ymin); if(i) // Не первая точка – строим линию от предыдущей rdsXGLineTo(ix,iy); else // Первая точка графика – делаем ее текущей rdsXGMoveTo(ix,iy); } // Отмена отсечения rdsXGSetClipRect(NULL); } } //========================================= // Отведение памяти под массивы void TSimplePlotData_a::AllocateArrays(void) { // Сначала нужно очистить массивы, если они были отведены ранее ClearArrays(); // При нулевом или отрицательном шаге записи отсчетов // работа блока невозможна if(TimeStep<=0.0) return; // Вычисление требуемого числа отсчетов по диапазону оси // времени и шагу записи Count=(Xmax-Xmin)/TimeStep+1; // Число отсчетов должно быть положительным if(Count<=0) {Count=0; return; } // Отведение памяти – по Count чисел double Times=new double[Count]; Values=new double[Count]; // Первый свободный индкс массива - 0 NextIndex=0; // Момент записи отсчета – начало диапазона оси времени NextTime=Xmin; } //========================================= // Освобождение массивов void TSimplePlotData_a::ClearArrays(void) { if(Count) // Массивы были отведены { delete[] Times; delete[] Values; } // Обнуление указателей и Count Times=Values=NULL; Count=NextIndex=0; } //========================================= // Добавление отсчета в массив void TSimplePlotData_a::AddPoint(double v) { double t; if(NextIndex>=Count) // Весь массив заполнен return; if(Time==NULL || Time->Data==NULL) // Нет доступа к “DynTime" return; // Получение значения времени из “DynTime" t=*((double*)Time->Data); if(t<NextTime) // Еще не пришло время писать отсчет return; // Достигнуто время записи Values[NextIndex]=v; Times[NextIndex]=t; NextIndex++; // Следующий отсчет – в следующий индекс NextTime+=TimeStep; // Время записи следующего отсчета } //========================================= // Сохранение параметров в текстовом виде void TSimplePlotData_a::SaveText(void) { RDS_HOBJECT ini; char *str; // Создание объекта для работы с текстом ini=rdsINICreateTextHolder(TRUE); // Создание в тексте секции "[General]" rdsSetObjectStr(ini,RDS_HINI_CREATESECTION,0,"General"); // Запись в секцию различных параметров rdsINIWriteDouble(ini,"TimeStep",TimeStep); rdsINIWriteDouble(ini,"Xmin",Xmin); rdsINIWriteDouble(ini,"Xmax",Xmax); rdsINIWriteDouble(ini,"XGridStep",XGridStep); rdsINIWriteInt(ini,"XNumDecimal",XNumDecimal); rdsINIWriteDouble(ini,"Ymin",Ymin); rdsINIWriteDouble(ini,"Ymax",Ymax); rdsINIWriteDouble(ini,"YGridStep",YGridStep); rdsINIWriteInt(ini,"YNumDecimal",YNumDecimal); // Создание в тексте секции "[Visuals]" rdsSetObjectStr(ini,RDS_HINI_CREATESECTION,0,"Visuals"); // Запись в секцию различных параметров rdsINIWriteInt(ini,"BorderColor",(int)BorderColor); rdsINIWriteInt(ini,"FillColor",(int)FillColor); rdsINIWriteInt(ini,"PlotBorderColor",(int)PlotBorderColor); rdsINIWriteInt(ini,"PlotFillColor",(int)PlotFillColor); rdsINIWriteInt(ini,"LineColor",(int)LineColor); rdsINIWriteInt(ini,"LineWidth",LineWidth); // Преобразование описания шрифта в строку для сохранения str=rdsStructToFontText(&Font,NULL); // Запись строки с описанием шрифта rdsINIWriteString(ini,"Font",str); rdsFree(str); // Освобождение памяти, занятой строкой // Запись сформированного текста в файл схемы или буфер обмена rdsCommandObject(ini,RDS_HINI_SAVEBLOCKTEXT); // Уничтожение вспомогательного объекта rdsDeleteObject(ini); } //========================================= // Загрузка параметров в текстовом виде из строки text void TSimplePlotData_a::LoadText(char *text) { RDS_HOBJECT ini; char *str; // Создание объекта для работы с текстом ini=rdsINICreateTextHolder(TRUE); // Загрузка текста в объект rdsSetObjectStr(ini,RDS_HINI_SETTEXT,0,text); // Если в тексте есть секция "General", загрузить из нее данные if(rdsINIOpenSection(ini,"General")) { TimeStep=rdsINIReadDouble(ini,"TimeStep",TimeStep); Xmin=rdsINIReadDouble(ini,"Xmin",Xmin); Xmax=rdsINIReadDouble(ini,"Xmax",Xmax); XGridStep=rdsINIReadDouble(ini,"XGridStep",XGridStep); XNumDecimal=rdsINIReadInt(ini,"XNumDecimal",XNumDecimal); Ymin=rdsINIReadDouble(ini,"Ymin",Ymin); Ymax=rdsINIReadDouble(ini,"Ymax",Ymax); YGridStep=rdsINIReadDouble(ini,"YGridStep",YGridStep); YNumDecimal=rdsINIReadInt(ini,"YNumDecimal",YNumDecimal); } // Если в тексте есть секция "Visuals", загрузить из нее данные if(rdsINIOpenSection(ini,"Visuals")) { BorderColor=(COLORREF)rdsINIReadInt(ini,"BorderColor", (int)BorderColor); FillColor=(COLORREF)rdsINIReadInt(ini,"FillColor", (int)FillColor); PlotBorderColor=(COLORREF)rdsINIReadInt(ini, "PlotBorderColor",(int)PlotBorderColor); PlotFillColor=(COLORREF)rdsINIReadInt(ini,"PlotFillColor", (int)PlotFillColor); LineColor=(COLORREF)rdsINIReadInt(ini,"LineColor", (int)LineColor); LineWidth=(COLORREF)rdsINIReadInt(ini,"LineWidth",LineWidth); str=rdsINIReadString(ini,"Font","",NULL); if(str) rdsFontTextToStruct(str,NULL,&Font); } // Уничтожение вспомогательного объекта rdsDeleteObject(ini); } //========================================= // Функция настройки параметров блока // ВАЖНО: Исходный текст программы должен быть записан в UTF8, // в противном случае необходимо использовать версии функций // с суффиксом "W" и символьные константы с префиксом "L" int TSimplePlotData_a::Setup(void) { RDS_HOBJECT window; BOOL ok; char *str; // Создание окна window=rdsFORMCreate(TRUE,-1,-1,"Простой график"); // Вкладка "Оси" rdsFORMAddTab(window,1,"Оси"); rdsFORMAddEdit(window,1,100, RDS_FORMCTRL_EDIT | RDS_FORMFLAG_LINE,"Шаг записи",50); rdsSetObjectDouble(window,100,RDS_FORMVAL_VALUE,TimeStep); // Текстовая метка без возможности ввода rdsFORMAddEdit(window,1,1,RDS_FORMCTRL_LABEL,"Ось X:",0); // Диапазон (два поля ввода в одной строке) rdsFORMAddEdit(window,1,2,RDS_FORMCTRL_RANGEEDIT,"Диапазон",90); rdsSetObjectDouble(window,2,RDS_FORMVAL_VALUE,Xmin); rdsSetObjectDouble(window,2,RDS_FORMVAL_RANGEMAX,Xmax); rdsFORMAddEdit(window,1,3,RDS_FORMCTRL_EDIT,"Шаг сетки",50); rdsSetObjectDouble(window,3,RDS_FORMVAL_VALUE,XGridStep); // Поле ввода со стрелками увеличения/уменьшения rdsFORMAddEdit(window,1,4, RDS_FORMCTRL_UPDOWN | RDS_FORMFLAG_LINE, "Дробная часть чисел",50); rdsSetObjectInt(window,4,RDS_FORMVAL_VALUE,XNumDecimal); rdsSetObjectInt(window,4,RDS_FORMVAL_UPDOWNMIN,0); rdsSetObjectInt(window,4,RDS_FORMVAL_UPDOWNMAX,5); rdsSetObjectInt(window,4,RDS_FORMVAL_UPDOWNINC,1); // Текстовая метка без возможности ввода rdsFORMAddEdit(window,1,5,RDS_FORMCTRL_LABEL,"Ось Y:",0); rdsFORMAddEdit(window,1,6,RDS_FORMCTRL_RANGEEDIT,"Диапазон",90); rdsSetObjectDouble(window,6,RDS_FORMVAL_VALUE,Ymin); rdsSetObjectDouble(window,6,RDS_FORMVAL_RANGEMAX,Ymax); rdsFORMAddEdit(window,1,7,RDS_FORMCTRL_EDIT,"Шаг сетки",50); rdsSetObjectDouble(window,7,RDS_FORMVAL_VALUE,YGridStep); rdsFORMAddEdit(window,1,8,RDS_FORMCTRL_UPDOWN, "Дробная часть чисел",50); rdsSetObjectInt(window,8,RDS_FORMVAL_VALUE,YNumDecimal); rdsSetObjectInt(window,8,RDS_FORMVAL_UPDOWNMIN,0); rdsSetObjectInt(window,8,RDS_FORMVAL_UPDOWNMAX,5); rdsSetObjectInt(window,8,RDS_FORMVAL_UPDOWNINC,1); // Вкладка "Внешний вид" rdsFORMAddTab(window,2,"Внешний вид"); rdsFORMAddEdit(window,2,9,RDS_FORMCTRL_COLOR,"Цвет рамки блока",50); rdsSetObjectInt(window,9,RDS_FORMVAL_VALUE,(int)BorderColor); rdsFORMAddEdit(window,2,10, RDS_FORMCTRL_COLOR | RDS_FORMFLAG_LINE,"Цвет фона блока",50); rdsSetObjectInt(window,10,RDS_FORMVAL_VALUE,(int)FillColor); rdsFORMAddEdit(window,2,11,RDS_FORMCTRL_COLOR,"Цвет рамки графика и сетки",50); rdsSetObjectInt(window,11,RDS_FORMVAL_VALUE,(int)PlotBorderColor); rdsFORMAddEdit(window,2,12,RDS_FORMCTRL_COLOR,"Цвет фона графика",50); rdsSetObjectInt(window,12,RDS_FORMVAL_VALUE,(int)PlotFillColor); rdsFORMAddEdit(window,2,13,RDS_FORMCTRL_COLOR,"Цвет линии графика",50); rdsSetObjectInt(window,13,RDS_FORMVAL_VALUE,(int)LineColor); rdsFORMAddEdit(window,2,14, RDS_FORMCTRL_UPDOWN | RDS_FORMFLAG_LINE, "Толщина линии графика",50); rdsSetObjectInt(window,14,RDS_FORMVAL_VALUE,LineWidth); rdsSetObjectInt(window,14,RDS_FORMVAL_UPDOWNMIN,0); rdsSetObjectInt(window,14,RDS_FORMVAL_UPDOWNMAX,5); rdsSetObjectInt(window,14,RDS_FORMVAL_UPDOWNINC,1); // Кнопка открытия диалога выбора шрифта rdsFORMAddEdit(window,2,15,RDS_FORMCTRL_FONTSELECT,"Шрифт чисел",0); // Преобразование шрифта в строку и занесение в поле ввода str=rdsStructToFontText(&Font,NULL); rdsSetObjectStr(window,15,RDS_FORMVAL_VALUE,str); rdsFree(str); // Открытие окна ok=rdsFORMShowModalEx(window,NULL); if(ok) { // Нажата кнопка OK - запись параметров обратно в блок Xmin=rdsGetObjectDouble(window,2,RDS_FORMVAL_VALUE); Xmax=rdsGetObjectDouble(window,2,RDS_FORMVAL_RANGEMAX); XGridStep=rdsGetObjectDouble(window,3,RDS_FORMVAL_VALUE); XNumDecimal=rdsGetObjectInt(window,4,RDS_FORMVAL_VALUE); TimeStep=rdsGetObjectDouble(window,100,RDS_FORMVAL_VALUE); Ymin=rdsGetObjectDouble(window,6,RDS_FORMVAL_VALUE); Ymax=rdsGetObjectDouble(window,6,RDS_FORMVAL_RANGEMAX); YGridStep=rdsGetObjectDouble(window,7,RDS_FORMVAL_VALUE); YNumDecimal=rdsGetObjectInt(window,8,RDS_FORMVAL_VALUE); BorderColor=(COLORREF)rdsGetObjectInt(window,9,RDS_FORMVAL_VALUE); FillColor=(COLORREF)rdsGetObjectInt(window,10,RDS_FORMVAL_VALUE); PlotBorderColor=(COLORREF)rdsGetObjectInt(window,11,RDS_FORMVAL_VALUE); PlotFillColor=(COLORREF)rdsGetObjectInt(window,12,RDS_FORMVAL_VALUE); LineColor=(COLORREF)rdsGetObjectInt(window,13,RDS_FORMVAL_VALUE); LineWidth=rdsGetObjectInt(window,14,RDS_FORMVAL_VALUE); // Получение параметров шрифта из строки str=rdsGetObjectStr(window,15,RDS_FORMVAL_VALUE); rdsFontTextToStruct(str,NULL,&Font); } // Уничтожение окна rdsDeleteObject(window); // Возвращаемое значение return ok?RDS_BFR_MODIFIED:RDS_BFR_DONE; } //========================================= //======================================================================= // Второй вариант оптимизации - перерисовываются изменения //======================================================================= //========================================= // Простой график – личная область данных //========================================= class TSimplePlotData { private: // Запомненные координаты поля графика int Gr_x1,Gr_x2,Gr_y1,Gr_y2; // Масштаб окна на момент последнего рисования double OldZoom;// Индекс последнего нарисованного отсчета int LastDrawnIndex;// Настроечные параметры графика (цвета, шаг и т.п.) double TimeStep; // Шаг записи отсчетов RDS_SERVFONTPARAMS Font; // Шрифт чисел на осях COLORREF BorderColor; // Цвет рамки вокруг блока COLORREF FillColor; // Цвет фона блока COLORREF PlotBorderColor;// Цвет рамки поля графика COLORREF PlotFillColor; // Цвет фона поля графика COLORREF LineColor; // Цвет лини графика int LineWidth; // Толщина линии графика // Ось X double Xmin,Xmax; // Диапазон double XGridStep; // Шаг чисел на осях int XNumDecimal; // Дробная часть чисел на осях // Ось Y double Ymin,Ymax; // Диапазон double YGridStep; // Шаг чисел на осях int YNumDecimal; // Дробная часть чисел на осях // Массивы для хранения отсчетов графика double *Times; // Массив отсчетов времени double *Values; // Массив значений int Count; // Размер массивов int NextIndex; // Индекс для записи следующего значения double NextTime; // Время записи следующего значения RDS_PDYNVARLINK Time; // Связь с динамической переменной // времени ("DynTime") public: // Функция сброса запомненного масштаба последнего рисования void ResetCoords(void){OldZoom=-1.0;}; // Функция отведения массивов отсчетов void AllocateArrays(void); // Функция освобождения массивов отсчетов void ClearArrays(void); // Добавление очередной точки в массив отсчетов графика void AddPoint(double v); int Setup(void); // Функция настройки параметров void SaveText(void); // Функция сохранения параметров void LoadText(char *text); // Функция загрузки параметров void Draw(RDS_PDRAWDATA DrawData); // Функция рисования TSimplePlotData(void); // Конструктор класса ~TSimplePlotData(); // Деструктор класса }; //========================================= // Модель блока extern "C" __declspec(dllexport) int RDSCALL SimplePlot( int CallMode, RDS_PBLOCKDATA BlockData, LPVOID 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))) // Указатель на личную область, приведенный к правильному типу TSimplePlotData *data=(TSimplePlotData*)(BlockData->BlockData); switch(CallMode) { // Инициализация блока case RDS_BFM_INIT: BlockData->BlockData=new TSimplePlotData(); break; // Очистка данных блока case RDS_BFM_CLEANUP: delete data; break; // Проверка типов статических переменных case RDS_BFM_VARCHECK: if(strcmp((char*)ExtParam,"{SSD}")==0) return RDS_BFR_DONE; return RDS_BFR_BADVARSMSG; // Функция настройки параметров case RDS_BFM_SETUP: data->ResetCoords(); // Сброс запомненных значений return data->Setup(); // Загрузка параметров в текстовом формате case RDS_BFM_LOADTXT: data->LoadText((char*)ExtParam); data->ResetCoords(); // Сброс запомненных значений break; // Созранение параметров в текстовом формате case RDS_BFM_SAVETXT: data->SaveText(); break; // Изменение размеров блока case RDS_BFM_RESIZE: data->ResetCoords(); // Сброс запомненных значений break; // Рисование внешнего вида блока case RDS_BFM_DRAW: //data->Draw((RDS_PDRAWDATA)ExtParam); data->DrawFast((RDS_PDRAWDATA)ExtParam); break; // Запуск расчета case RDS_BFM_STARTCALC: if(((RDS_PSTARTSTOPDATA)ExtParam)->FirstStart) data->AllocateArrays(); // Первый запуск break; // Сброс расчета case RDS_BFM_RESETCALC: data->ClearArrays(); break; // Реакция на изменение динамической переменной case RDS_BFM_DYNVARCHANGE: data->AddPoint(x); break; } return RDS_BFR_DONE; // Отмена макроопределений для переменных #undef x #undef Ready #undef Start #undef pStart } //========================================= // Конструктор класса личной области данных графика TSimplePlotData::TSimplePlotData(void) { // Инициализация OldZoom: значение -1 приведет к принудительному // вычислению Gr_x1,Gr_x2,Gr_y1 и Gr_y2 в ближайшем вызове // функции Draw OldZoom=-1.0;// Инициализация LastDrawnIndex LastDrawnIndex=-1;// Присвоение начальных значений параметрам TimeStep=0.1; // Шаг записи BorderColor=0; // Цвет рамки вокруг блока FillColor=0xffffff; // Цвет фона блока PlotBorderColor=0; // Цвет рамки окна графика и сетки PlotFillColor=0xffffff; // Цвет окна графика LineColor=0; // Цвет линии графика LineWidth=1; // Толщина линии графика // Параметры шрифта Font.servSize=sizeof(Font); strcpy(Font.Name,"Arial"); Font.SizePriority=FALSE; Font.Height=15; Font.Color=0; Font.Bold=Font.Italic=Font.Underline=Font.StrikeOut=FALSE; Font.CharSet=DEFAULT_CHARSET; // Диапазоны осей, шаг сетки, число десятичных знаков // в числах на осях Xmin=0.0; Xmax=10.0; XGridStep=5.0; XNumDecimal=0; Ymin=-1.0; Ymax=1.0; YGridStep=0.5; YNumDecimal=1; // Обнуление указателей на массивы и их размера // (массивы еще не отведены) Times=Values=NULL; Count=NextIndex=0; NextTime=Xmin; // Подписка на динамическую переменную времени Time=rdsSubscribeToDynamicVar( RDS_DVPARENT, // В родительской подсистеме "DynTime", // Имя переменной "D", // Тип переменной (double) TRUE); // Искать по иерархии } //========================================= // Деструктор класса TSimplePlotData::~TSimplePlotData() { rdsUnsubscribeFromDynamicVar(Time); // Прекратить подписку ClearArrays(); // Освободить массивы } //========================================= // Рисование внешнего вида блока void TSimplePlotData::Draw(RDS_PDRAWDATA DrawData) { // Вспомогательные переменные // int Gr_x1,Gr_x2,Gr_y1,Gr_y2; - эти переменные стали полями класса int x1,y1,x2,y2,textheight,w1,w2; char buf[80]; // Рамка графика rdsXGSetPenStyle(0,PS_SOLID,1,BorderColor,R2_COPYPEN); rdsXGSetBrushStyle(0,RDS_GFS_SOLID,FillColor); rdsXGRectangle(DrawData->Left,DrawData->Top, DrawData->Left+DrawData->Width, DrawData->Top+DrawData->Height); // Необходимо вычислить координаты поля графика относительно // верхнего левого угла блока // Установка параметров шрифта с учетом масштаба rdsXGSetFontByParStr(&Font,DrawData->DoubleZoom); rdsXGGetTextSize("0",NULL,&textheight); if(DrawData->DoubleZoom!=OldZoom) // Масштаб изменен { // Зазор сверху – половина высоты цифры + 1 точка Gr_y1=textheight/2+1; // Зазор снизу – полная высота цифры + 1 точка Gr_y2=DrawData->Height-textheight-1; // Зазор слева – ширина самого длинного числа вертикальной // оси или половина ширины Xmin sprintf(buf," %.*lf ",YNumDecimal,Ymin); rdsXGGetTextSize(buf,&w1,NULL); // Ширина Ymin sprintf(buf," %.*lf ",YNumDecimal,Ymax); rdsXGGetTextSize(buf,&w2,NULL); // Ширина Ymax if(w2>w1) w1=w2; sprintf(buf," %.*lf ",XNumDecimal,Xmin); rdsXGGetTextSize(buf,&w2,NULL); // Ширина Xmin w2/=2; if(w2>w1) w1=w2; Gr_x1=w1; // Зазор справа – половина ширины Xmax sprintf(buf," %.*lf ",XNumDecimal,Xmax); rdsXGGetTextSize(buf,&w2,NULL); // Ширина Xmax w2/=2; Gr_x2=DrawData->Width-w2; // Запоминание нового масштаба OldZoom=DrawData->DoubleZoom; } // if(DrawData->DoubleZoom!=OldZoom) // Абсолютные (на рабочем поле) координаты поля графика x1=DrawData->Left+Gr_x1; x2=DrawData->Left+Gr_x2; y1=DrawData->Top+Gr_y1; y2=DrawData->Top+Gr_y2; if(x1>=x2 || y1>=y2) // Негде рисовать return; // Прямоугольник поля графика rdsXGSetPenStyle(0,PS_SOLID,1,PlotBorderColor,R2_COPYPEN); rdsXGSetBrushStyle(0,RDS_GFS_SOLID,PlotFillColor); rdsXGRectangle(x1,y1,x2,y2); // Установка пунктирного стиля линии rdsXGSetPenStyle(0,PS_DOT,1,PlotBorderColor,R2_COPYPEN); rdsXGSetBrushStyle(0,RDS_GFS_EMPTY,0); // Без заливки // Горизонтальная ось с сеткой for(double x=Xmin;x<=Xmax+XGridStep*0.5;x+=XGridStep) { // ix - координата линии на рабочем поле int ix=x1+(x-Xmin)*(x2-x1)/(Xmax-Xmin); if(ix>x1 && ix<x2) // Чертим вертикальную линию { rdsXGMoveTo(ix,y1); rdsXGLineTo(ix,y2); } // Вывод числа на оси под полем sprintf(buf,"%.*lf",XNumDecimal,x); rdsXGGetTextSize(buf,&w1,NULL); rdsXGTextOut(ix-w1/2,y2,buf); } // Вертикальная ось с сеткой for(double y=Ymin;y<=Ymax+YGridStep*0.5;y+=YGridStep) { // iy - координата линии на рабочем поле int iy=y2-(y-Ymin)*(y2-y1)/(Ymax-Ymin); if(iy>y1 && iy<y2) // Чертим горизонтальную линию { rdsXGMoveTo(x1,iy); rdsXGLineTo(x2,iy); } // Вывод числа на оси слева от поля sprintf(buf,"%.*lf ",YNumDecimal,y); rdsXGGetTextSize(buf,&w1,&textheight); rdsXGTextOut(x1-w1-2,iy-textheight/2,buf); } // Если массивы не пустые – рисовать график if(Count) { RECT r; // Установить область отсечения рисования по полю графика r.left=x1+1; r.top=y1+1; r.right=x2-1; r.bottom=y2-1; rdsXGSetClipRect(&r); // Установить сплошной стиль линии, заданный для // графика цвет и толщину линии с учетом масштаба rdsXGSetPenStyle(0,PS_SOLID, LineWidth*DrawData->DoubleZoom, LineColor,R2_COPYPEN); // Строим ломанную линию по отсчетам из массивов for(int i=0;i<NextIndex;i++) { // Преобразуем вещественные отсчеты в целочисленные // координаты на рабочем поле int ix=x1+(Times[i]-Xmin)*(x2-x1)/(Xmax-Xmin), iy=y2-(Values[i]-Ymin)*(y2-y1)/(Ymax-Ymin); if(i) // Не первая точка – строим линию от предыдущей rdsXGLineTo(ix,iy); else // Первая точка графика – делаем ее текущей rdsXGMoveTo(ix,iy); }// Запоминаем последний нарисованный отсчет LastDrawnIndex=NextIndex-1;// Отмена отсечения rdsXGSetClipRect(NULL); } } //=========================================// Рисование изменений void TSimplePlotData::DrawFast(RDS_PDRAWDATA DrawData) { int x1,y1,x2,y2; // Если RDS требует полного рисования, или полное рисование // еще не проводилось, вызывается старая функция Draw if(DrawData->FullDraw || DrawData->DoubleZoom!=OldZoom) { Draw(DrawData); return; } // Вычисление абсолютных координат поля графика x1=DrawData->Left+Gr_x1; x2=DrawData->Left+Gr_x2; y1=DrawData->Top+Gr_y1; y2=DrawData->Top+Gr_y2; if(x1>=x2 || y1>=y2) // Негде рисовать return; // Если массивы не пустые – рисовать график, начиная // с последней уже нарисованной точки if(Count) { RECT r; // Установить область отсечения рисования по полю графика r.left=x1+1; r.top=y1+1; r.right=x2-1; r.bottom=y2-1; rdsXGSetClipRect(&r); // Установить сплошной стиль линии, заданный для // графика цвет и толщину линии с учетом масштаба rdsXGSetPenStyle(0,PS_SOLID, LineWidth*DrawData->DoubleZoom, LineColor,R2_COPYPEN); // Проверка допустимости LastDrawnIndex – на всякий случай if(LastDrawnIndex<0) LastDrawnIndex=0; // Строим ломанную линию по отсчетам из массивов, // начиная с LastDrawIndex for(int i=LastDrawnIndex;i<NextIndex;i++) { int ix=x1+(Times[i]-Xmin)*(x2-x1)/(Xmax-Xmin), iy=y2-(Values[i]-Ymin)*(y2-y1)/(Ymax-Ymin); if(i!=LastDrawnIndex) rdsXGLineTo(ix,iy); else rdsXGMoveTo(ix,iy); } // Запоминаем последний нарисованный отсчет LastDrawnIndex=NextIndex-1; // Отмена отсечения rdsXGSetClipRect(NULL); } } //=========================================// Отведение памяти под массивы void TSimplePlotData::AllocateArrays(void) { // Сначала нужно очистить массивы, если они были отведены ранее ClearArrays(); // При нулевом или отрицательном шаге записи отсчетов // работа блока невозможна if(TimeStep<=0.0) return; // Вычисление требуемого числа отсчетов по диапазону оси // времени и шагу записи Count=(Xmax-Xmin)/TimeStep+1; // Число отсчетов должно быть положительным if(Count<=0) {Count=0; return; } // Отведение памяти – по Count чисел double Times=new double[Count]; Values=new double[Count]; // Первый свободный индкс массива - 0 NextIndex=0; // Момент записи отсчета – начало диапазона оси времени NextTime=Xmin; } //========================================= // Освобождение массивов void TSimplePlotData::ClearArrays(void) { if(Count) // Массивы были отведены { delete[] Times; delete[] Values; } // Обнуление указателей и Count Times=Values=NULL; Count=NextIndex=0; } //========================================= // Добавление отсчета в массив void TSimplePlotData::AddPoint(double v) { double t; if(NextIndex>=Count) // Весь массив заполнен return; if(Time==NULL || Time->Data==NULL) // Нет доступа к “DynTime" return; // Получение значения времени из “DynTime" t=*((double*)Time->Data); if(t<NextTime) // Еще не пришло время писать отсчет return; // Достигнуто время записи Values[NextIndex]=v; Times[NextIndex]=t; NextIndex++; // Следующий отсчет – в следующий индекс NextTime+=TimeStep; // Время записи следующего отсчета } //========================================= // Сохранение параметров в текстовом виде void TSimplePlotData::SaveText(void) { RDS_HOBJECT ini; char *str; // Создание объекта для работы с текстом ini=rdsINICreateTextHolder(TRUE); // Создание в тексте секции "[General]" rdsSetObjectStr(ini,RDS_HINI_CREATESECTION,0,"General"); // Запись в секцию различных параметров rdsINIWriteDouble(ini,"TimeStep",TimeStep); rdsINIWriteDouble(ini,"Xmin",Xmin); rdsINIWriteDouble(ini,"Xmax",Xmax); rdsINIWriteDouble(ini,"XGridStep",XGridStep); rdsINIWriteInt(ini,"XNumDecimal",XNumDecimal); rdsINIWriteDouble(ini,"Ymin",Ymin); rdsINIWriteDouble(ini,"Ymax",Ymax); rdsINIWriteDouble(ini,"YGridStep",YGridStep); rdsINIWriteInt(ini,"YNumDecimal",YNumDecimal); // Создание в тексте секции "[Visuals]" rdsSetObjectStr(ini,RDS_HINI_CREATESECTION,0,"Visuals"); // Запись в секцию различных параметров rdsINIWriteInt(ini,"BorderColor",(int)BorderColor); rdsINIWriteInt(ini,"FillColor",(int)FillColor); rdsINIWriteInt(ini,"PlotBorderColor",(int)PlotBorderColor); rdsINIWriteInt(ini,"PlotFillColor",(int)PlotFillColor); rdsINIWriteInt(ini,"LineColor",(int)LineColor); rdsINIWriteInt(ini,"LineWidth",LineWidth); // Преобразование описания шрифта в строку для сохранения str=rdsStructToFontText(&Font,NULL); // Запись строки с описанием шрифта rdsINIWriteString(ini,"Font",str); rdsFree(str); // Освобождение памяти, занятой строкой // Запись сформированного текста в файл схемы или буфер обмена rdsCommandObject(ini,RDS_HINI_SAVEBLOCKTEXT); // Уничтожение вспомогательного объекта rdsDeleteObject(ini); } //========================================= // Загрузка параметров в текстовом виде из строки text void TSimplePlotData::LoadText(char *text) { RDS_HOBJECT ini; char *str; // Создание объекта для работы с текстом ini=rdsINICreateTextHolder(TRUE); // Загрузка текста в объект rdsSetObjectStr(ini,RDS_HINI_SETTEXT,0,text); // Если в тексте есть секция "General", загрузить из нее данные if(rdsINIOpenSection(ini,"General")) { TimeStep=rdsINIReadDouble(ini,"TimeStep",TimeStep); Xmin=rdsINIReadDouble(ini,"Xmin",Xmin); Xmax=rdsINIReadDouble(ini,"Xmax",Xmax); XGridStep=rdsINIReadDouble(ini,"XGridStep",XGridStep); XNumDecimal=rdsINIReadInt(ini,"XNumDecimal",XNumDecimal); Ymin=rdsINIReadDouble(ini,"Ymin",Ymin); Ymax=rdsINIReadDouble(ini,"Ymax",Ymax); YGridStep=rdsINIReadDouble(ini,"YGridStep",YGridStep); YNumDecimal=rdsINIReadInt(ini,"YNumDecimal",YNumDecimal); } // Если в тексте есть секция "Visuals", загрузить из нее данные if(rdsINIOpenSection(ini,"Visuals")) { BorderColor=(COLORREF)rdsINIReadInt(ini,"BorderColor", (int)BorderColor); FillColor=(COLORREF)rdsINIReadInt(ini,"FillColor", (int)FillColor); PlotBorderColor=(COLORREF)rdsINIReadInt(ini, "PlotBorderColor",(int)PlotBorderColor); PlotFillColor=(COLORREF)rdsINIReadInt(ini,"PlotFillColor", (int)PlotFillColor); LineColor=(COLORREF)rdsINIReadInt(ini,"LineColor", (int)LineColor); LineWidth=(COLORREF)rdsINIReadInt(ini,"LineWidth",LineWidth); str=rdsINIReadString(ini,"Font","",NULL); if(str) rdsFontTextToStruct(str,NULL,&Font); } // Уничтожение вспомогательного объекта rdsDeleteObject(ini); } //========================================= // Функция настройки параметров блока // ВАЖНО: Исходный текст программы должен быть записан в UTF8, // в противном случае необходимо использовать версии функций // с суффиксом "W" и символьные константы с префиксом "L" int TSimplePlotData::Setup(void) { RDS_HOBJECT window; BOOL ok; char *str; // Создание окна window=rdsFORMCreate(TRUE,-1,-1,"Простой график"); // Вкладка "Оси" rdsFORMAddTab(window,1,"Оси"); rdsFORMAddEdit(window,1,100, RDS_FORMCTRL_EDIT | RDS_FORMFLAG_LINE,"Шаг записи",50); rdsSetObjectDouble(window,100,RDS_FORMVAL_VALUE,TimeStep); // Текстовая метка без возможности ввода rdsFORMAddEdit(window,1,1,RDS_FORMCTRL_LABEL,"Ось X:",0); // Диапазон (два поля ввода в одной строке) rdsFORMAddEdit(window,1,2,RDS_FORMCTRL_RANGEEDIT,"Диапазон",90); rdsSetObjectDouble(window,2,RDS_FORMVAL_VALUE,Xmin); rdsSetObjectDouble(window,2,RDS_FORMVAL_RANGEMAX,Xmax); rdsFORMAddEdit(window,1,3,RDS_FORMCTRL_EDIT,"Шаг сетки",50); rdsSetObjectDouble(window,3,RDS_FORMVAL_VALUE,XGridStep); // Поле ввода со стрелками увеличения/уменьшения rdsFORMAddEdit(window,1,4, RDS_FORMCTRL_UPDOWN | RDS_FORMFLAG_LINE, "Дробная часть чисел",50); rdsSetObjectInt(window,4,RDS_FORMVAL_VALUE,XNumDecimal); rdsSetObjectInt(window,4,RDS_FORMVAL_UPDOWNMIN,0); rdsSetObjectInt(window,4,RDS_FORMVAL_UPDOWNMAX,5); rdsSetObjectInt(window,4,RDS_FORMVAL_UPDOWNINC,1); // Текстовая метка без возможности ввода rdsFORMAddEdit(window,1,5,RDS_FORMCTRL_LABEL,"Ось Y:",0); rdsFORMAddEdit(window,1,6,RDS_FORMCTRL_RANGEEDIT,"Диапазон",90); rdsSetObjectDouble(window,6,RDS_FORMVAL_VALUE,Ymin); rdsSetObjectDouble(window,6,RDS_FORMVAL_RANGEMAX,Ymax); rdsFORMAddEdit(window,1,7,RDS_FORMCTRL_EDIT,"Шаг сетки",50); rdsSetObjectDouble(window,7,RDS_FORMVAL_VALUE,YGridStep); rdsFORMAddEdit(window,1,8,RDS_FORMCTRL_UPDOWN, "Дробная часть чисел",50); rdsSetObjectInt(window,8,RDS_FORMVAL_VALUE,YNumDecimal); rdsSetObjectInt(window,8,RDS_FORMVAL_UPDOWNMIN,0); rdsSetObjectInt(window,8,RDS_FORMVAL_UPDOWNMAX,5); rdsSetObjectInt(window,8,RDS_FORMVAL_UPDOWNINC,1); // Вкладка "Внешний вид" rdsFORMAddTab(window,2,"Внешний вид"); rdsFORMAddEdit(window,2,9,RDS_FORMCTRL_COLOR,"Цвет рамки блока",50); rdsSetObjectInt(window,9,RDS_FORMVAL_VALUE,(int)BorderColor); rdsFORMAddEdit(window,2,10, RDS_FORMCTRL_COLOR | RDS_FORMFLAG_LINE,"Цвет фона блока",50); rdsSetObjectInt(window,10,RDS_FORMVAL_VALUE,(int)FillColor); rdsFORMAddEdit(window,2,11,RDS_FORMCTRL_COLOR,"Цвет рамки графика и сетки",50); rdsSetObjectInt(window,11,RDS_FORMVAL_VALUE,(int)PlotBorderColor); rdsFORMAddEdit(window,2,12,RDS_FORMCTRL_COLOR,"Цвет фона графика",50); rdsSetObjectInt(window,12,RDS_FORMVAL_VALUE,(int)PlotFillColor); rdsFORMAddEdit(window,2,13,RDS_FORMCTRL_COLOR,"Цвет линии графика",50); rdsSetObjectInt(window,13,RDS_FORMVAL_VALUE,(int)LineColor); rdsFORMAddEdit(window,2,14, RDS_FORMCTRL_UPDOWN | RDS_FORMFLAG_LINE, "Толщина линии графика",50); rdsSetObjectInt(window,14,RDS_FORMVAL_VALUE,LineWidth); rdsSetObjectInt(window,14,RDS_FORMVAL_UPDOWNMIN,0); rdsSetObjectInt(window,14,RDS_FORMVAL_UPDOWNMAX,5); rdsSetObjectInt(window,14,RDS_FORMVAL_UPDOWNINC,1); // Кнопка открытия диалога выбора шрифта rdsFORMAddEdit(window,2,15,RDS_FORMCTRL_FONTSELECT,"Шрифт чисел",0); // Преобразование шрифта в строку и занесение в поле ввода str=rdsStructToFontText(&Font,NULL); rdsSetObjectStr(window,15,RDS_FORMVAL_VALUE,str); rdsFree(str); // Открытие окна ok=rdsFORMShowModalEx(window,NULL); if(ok) { // Нажата кнопка OK - запись параметров обратно в блок Xmin=rdsGetObjectDouble(window,2,RDS_FORMVAL_VALUE); Xmax=rdsGetObjectDouble(window,2,RDS_FORMVAL_RANGEMAX); XGridStep=rdsGetObjectDouble(window,3,RDS_FORMVAL_VALUE); XNumDecimal=rdsGetObjectInt(window,4,RDS_FORMVAL_VALUE); TimeStep=rdsGetObjectDouble(window,100,RDS_FORMVAL_VALUE); Ymin=rdsGetObjectDouble(window,6,RDS_FORMVAL_VALUE); Ymax=rdsGetObjectDouble(window,6,RDS_FORMVAL_RANGEMAX); YGridStep=rdsGetObjectDouble(window,7,RDS_FORMVAL_VALUE); YNumDecimal=rdsGetObjectInt(window,8,RDS_FORMVAL_VALUE); BorderColor=(COLORREF)rdsGetObjectInt(window,9,RDS_FORMVAL_VALUE); FillColor=(COLORREF)rdsGetObjectInt(window,10,RDS_FORMVAL_VALUE); PlotBorderColor=(COLORREF)rdsGetObjectInt(window,11,RDS_FORMVAL_VALUE); PlotFillColor=(COLORREF)rdsGetObjectInt(window,12,RDS_FORMVAL_VALUE); LineColor=(COLORREF)rdsGetObjectInt(window,13,RDS_FORMVAL_VALUE); LineWidth=rdsGetObjectInt(window,14,RDS_FORMVAL_VALUE); // Получение параметров шрифта из строки str=rdsGetObjectStr(window,15,RDS_FORMVAL_VALUE); rdsFontTextToStruct(str,NULL,&Font); } // Уничтожение окна rdsDeleteObject(window); // Возвращаемое значение return ok?RDS_BFR_MODIFIED:RDS_BFR_DONE; } //=========================================