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

Полный исходный текст на языке C++ для библиотеки (DLL) с моделью блока-генератора синусоиды, косинусоиды или прямоугольных импульсов, выводящего всплывающую подсказку со значениями своих параметров. Изменения относительно примера из §2.8.3 выделены цветом.

  // Генератор с всплывающей подсказкой
  #include <windows.h>
  #include <math.h>
  #include <stdio.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;
  }
  //========= Конец главной функции =========

  //=========================================
  //=             Генератор                 =
  //=========================================

  //====== Класс личной области данных ======
  class TTestGenData
  { public:
      int Type;         // Тип (0-sin,1-cos,2-прямоугольные)
      double Period;    // Период
      double Impulse;   // Длительность импульса

       Time;  // Связь с динамической
                             // переменной времени

      int Setup(void);      // Функция настройки
      void SaveText(void);  // Сохранение параметров
      void LoadText(char *text);// Загрузка параметров
      void PopupHint(void);     // Всплывающая подсказка  
      TTestGenData(void)    // Конструктор класса
        { Type=0; Period=1.0; Impulse=0.5;
          // Подписка на динамическую переменную времени
          Time=(,
                                        "DynTime",
                                        "D",
                                        TRUE);
        };
      ~TTestGenData(void)	// Деструктор класса
        { // Прекращение подписки
          (Time);
        };
  };

  //==== Прототип функции обратного вызова окна настроек ====
  void  TestGenDataCheckFunc2( win,
                                      data);

  //====== Функция редактирования параметров ======
  // 
  // 
  // 
  int TTestGenData::Setup(void)
  {  window; // Идентификатор вспомогательного объекта
     ok;            // Пользователь нажал "OK"
    // Создание окна
    window=(FALSE,-1,-1,"Простой генератор");
    // Добавление полей ввода
    (window,0,1,,
                   "Вид:",210);
    (window,0,2,,
                   "Период:",80);
    (window,0,3,,
                   "Длительность:",80);
    // Установка списка вариантов
    (window,1,,
                    "Синус\nКосинус\nПрямоугольные импульсы");
    // Занесение исходных значений в поля ввода
    (window,1,,Type);
    (window,2,,Period);
    (window,3,,Impulse);
    // Включение дополнительной панели слева от полей ввода
    (window,1,-1);
    // Добавление области для рисования графика
    (window,1,4,,NULL,100);
    // Автоматическое вычисление высоты этой области
    (window,4,,-1);
    // Открытие окна с другой функцией обратного вызова
    ok=(window,TestGenDataCheckFunc2);

    if(ok)
      { // Нажата кнопка OK - запись параметров обратно в блок
        Type=(window,1,);
        Period=(window,2,);
        Impulse=(window,3,);
      }
    // Уничтожение окна
    (window);
    // Возвращаемое значение
    return ok?:;
  }

  //====== Функция обратного вызова для окна настроек ======
  void  TestGenDataCheckFunc2( win,
                                      data)
  { // Считать номер пункта выпадающего списка
    int type=(win,1,);
    // Вспомогательные переменные для рисования графика
    int y0,y_ampl,x0,x1;
    double pix_period;

    switch(data->Event)
      { // Изменение поля ввода
        case :
          // Запретить ввод длительности импульса для sin и cos
          (win,3,,type==2);
          // Перерисовать график
          (win,);
          break;

        // Рисование
        case :
          // Заливка фона белым цветом
          (0,RDS_GFS_SOLID,0xffffff);
          (data->Left,
                        data->Top,
                        data->Left+data->Width,
                        data->Top+data->Height);
          // Координаты рисования
          x0=data->Left+10;               // Начало графика
          x1=data->Left+data->Width-10;// Конец графика
          y0=data->Top+data->Height/2; // Центр по вертикали
          y_ampl=(data->Height-20)/2;     // Амплитуда
          pix_period=0.5*(x1-x0);            // Период на рисунке
          // Координатные оси
          (0,,1,0,);
          (data->Left+5,y0);
          (data->Left+data->Width-5,y0);
          (x0,data->Top+5);
          (x0,data->Top+data->Height-5);
          // График
          (,0,3,0,0);
          if(type==2) // Прямоугольные импульсы
            { double period,impulse,pix_impulse;
              // Чтение введенных пользователем значений
              period=(win,2,);
              impulse=(win,3,);
              if(period==0.0) // Нельзя вычислить частоту
                return;
              // Длительность импульса на рисунке
              pix_impulse=impulse*pix_period/period;
              // Первый период
              (x0,y0+y_ampl);
              (x0,y0-y_ampl);
              (x0+pix_impulse,y0-y_ampl);
              (x0+pix_impulse,y0+y_ampl);
              (x0+pix_period,y0+y_ampl);
              // Второй период
              (x0+pix_period,y0-y_ampl);
              (x0+pix_period+pix_impulse,y0-y_ampl);
              (x0+pix_period+pix_impulse,y0+y_ampl);
              (x1,y0+y_ampl);
            }
          else // Синус или косинус
            { double t,y;
              // Цикл по горизонтали с шагом в 3 точки
              for(int x=x0;x<=x1;x+=3)
                { t=2*M_PI*(x-x0)/pix_period;
                  y=y_ampl*((type==0)?sin(t):cos(t));
                  if(x==x0) // Первая точка – установить позицию
                    (x,y0-y);
                  else // Рисовать линию от предыдущей точки
                    (x,y0-y);
                } // for(int x=x0...)
            }
          break;
      } // switch
  }
  //=========================================

  //============= Модель блока ==============
  extern "C" __declspec(dllexport)
    int  TestGen(int CallMode,
                         BlockData,
                         ExtParam)
  {
  // 
  #define pStart ((char *)(BlockData->VarTreeData))
  #define Start (*((char *)(pStart)))
  #define Ready (*((char *)(pStart+RDS_VSZ_S)))
  #define y (*((double *)(pStart+2*RDS_VSZ_S)))
    // Вспомогательная переменная – указатель на личную область
    // данных блока, приведенный к правильному типу
    TTestGenData *data;

    switch(CallMode)
      { // Инициализация
        case :
          BlockData->BlockData=new TTestGenData();
          break;

        // Очистка
        case :
          data=(TTestGenData*)(BlockData->BlockData);
          delete data;
          break;

// Всплывающая подсказка case : data=(TTestGenData*)(BlockData->BlockData); data->PopupHint(); break;
// Проверка типа переменных case : if(strcmp((char*)ExtParam,"{SSD}")==0) return ; return ; // Запись параметров в текстовом формате case : data=(TTestGenData*)(BlockData->BlockData); data->SaveText(); break; // Загрузка параметров в текстовом формате case : data=(TTestGenData*)(BlockData->BlockData); data->LoadText((char*)ExtParam); break; // Функция настройки case : data=(TTestGenData*)(BlockData->BlockData); return data->Setup(); // Изменение динамической переменной или запуск расчета case : case : data=(TTestGenData*)(BlockData->BlockData); if(data->Period==0.0) // Нельзя вычислить частоту return 0; // Проверка наличия переменной “DynTime" if(data->Time!=NULL && data->Time->Data!=NULL) { // Динамическая переменная найдена – чтение значения double t=*((double*)data->Time->Data); switch(data->Type) { case 0: // Синус y=sin(2*M_PI*t/data->Period); break; case 1: // Косинус y=cos(2*M_PI*t/data->Period); break; case 2: // Прямоугольные импульсы t=fmod(t,data->Period); y=(t>data->Impulse)?-1.0:1.0; break; } // Взвести Ready для передачи выхода по связям Ready=1; } break; } return ; // Отмена макроопределений #undef y #undef Ready #undef Start #undef pStart } //========================================= // Глобальный массив ключевых слов // Индексы 0 1 2 const char *TestGen_Keywords[]={"type","period","impulse",NULL}; // define-константы для индексов #define TESTGEN_KW_TYPE 0 #define TESTGEN_KW_PERIOD 1 #define TESTGEN_KW_IMPULSE 2 //========================================= // Функция сохранения параметров void TTestGenData::SaveText(void) { // Запись "type" и целого значения (TestGen_Keywords[TESTGEN_KW_TYPE],Type); // Запись "period" и вещественного значения (TestGen_Keywords[TESTGEN_KW_PERIOD], Period); // Запись "impulse" и вещественного значения if(Type==2) (TestGen_Keywords[TESTGEN_KW_IMPULSE], Impulse); } //========================================= // Функция загрузки параметров void TTestGenData::LoadText(char *text) { Parser; // Вспомогательный объект work=TRUE; // Флаг цикла // Создание объекта для разбора текста Parser=(TRUE); // Передача объекту массива ключевых слов (Parser,TestGen_Keywords,-1,0); // Передача объекту разбираемого текста (Parser,,0,text); // Цикл до тех пор, пока в тексте не кончатся слова while(work) { int id; // Уникальный идентификатор слова // Извлечь из текста и опознать слово id=(Parser,NULL,NULL,NULL,TRUE); // Действия в зависимости от слова switch(id) { // Нет слова – конец текста case : work=FALSE; // Выйти из цикла break; // Перевод строки – пропускаем case : break; // Слово "type" case TESTGEN_KW_TYPE: // Извлекаем следующее слово и переводим в целое Type=(Parser,,TRUE); break; // Слово "period" case TESTGEN_KW_PERIOD: // Извлекаем следующее слово и переводим в double Period=(Parser,,TRUE); break; // Слово "impulse" case TESTGEN_KW_IMPULSE: // Извлекаем следующее слово и переводим в double Impulse=(Parser,,TRUE); break; default: // Слово не опознано – ошибка work=FALSE; // Выйти из цикла } // Конец switch(...) } // Конец while(work) // Удаление вспомогательного объекта (Parser); } //=========================================
// Вывод всплывающей подсказки // // // void TTestGenData::PopupHint(void) { // Есть ли доступ к переменной времени? if(Time==NULL || Time->Data==NULL) // Доступа нет ("ОШИБКА: в схеме нет переменной DynTime"); else // Доступ есть { char *str=NULL, *period=(Period,-1,NULL), *impulse=(Impulse,-1,NULL); switch(Type) { case 0: // Синус str=("Генератор - синус\nПериод: ", period,FALSE); break; case 1: // Косинус str=("Генератор – косинус\nПериод: ", period,FALSE); break; case 2: // Импульсы str=("Генератор – прямоугольные импульсы\n" "Период: ",period,FALSE); (&str,"\nДлительность импульса: ",FALSE); (&str,impulse,FALSE); break; } // Установка текста подсказки (str); // Освобождение памяти, занятой динамическими строками (str); (period); (impulse); } } //=================================================

Полный исходный текст на языке C++ для библиотеки (DLL) с моделью блока-графика, показывающего всплывающую подсказку с координатами точки графика под курсором мыши. Изменения относительно модели из §2.10.3 выделены цветом.

  //  График с всплывающей подсказкой
  #include <windows.h>
  #include <stdio.h>
  #include <math.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;
  }
  //========= Конец главной функции =========

  //=========================================
  // Простой график – личная область данных
  //=========================================
  class TSimplePlotData
  { private:
      // Запомненные координаты поля графика
      int Gr_x1,Gr_x2,Gr_y1,Gr_y2;
      // Масштаб окна на момент последнего рисования
      double OldZoom;
      // Индекс последнего нарисованного отсчета
      int LastDrawnIndex;

      // Настроечные параметры графика (цвета, шаг и т.п.)
      double TimeStep;         // Шаг записи отсчетов
       Font; // Шрифт чисел на осях
       BorderColor;    // Цвет рамки вокруг блока
       FillColor;      // Цвет фона блока
       PlotBorderColor;// Цвет рамки поля графика
       PlotFillColor;  // Цвет фона поля графика
       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;         // Время записи следующего значения

       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( DrawData); // Функция рисования
      void DrawFast( DrawData); // Функция быстрого рисования
      // Рисование иконки при отсутствии доступа к DynTime
      void DrawAdditional( DrawData);
// Поиск индекса отсчета, соответствующего времени t int FindTimeIndex(double t); // Вывод всплывающей полсказки void PopupHint( hintdata);
TSimplePlotData(void); // Конструктор класса ~TSimplePlotData(); // Деструктор класса }; //========================================= // Модель блока extern "C" __declspec(dllexport) int SimplePlot( int CallMode, BlockData, ExtParam) { // #define pStart ((char *)(BlockData->VarTreeData)) #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 : BlockData->BlockData=new TSimplePlotData(); break; // Очистка данных блока case : delete data; break; // Проверка типов статических переменных case : if(strcmp((char*)ExtParam,"{SSD}")==0) return ; return ;
// Всплывающая подсказка case : data->PopupHint(()ExtParam); break;
// Функция настройки параметров case : data->ResetCoords(); // Сброс запомненных значений return data->Setup(); // Загрузка параметров в текстовом формате case : data->LoadText((char*)ExtParam); data->ResetCoords(); // Сброс запомненных значений break; // Созранение параметров в текстовом формате case : data->SaveText(); break; // Изменение размеров блока case : data->ResetCoords(); // Сброс запомненных значений break; // Рисование внешнего вида блока case : //data->Draw(()ExtParam); data->DrawFast(()ExtParam); break; // Дополнительное рисование case : data->DrawAdditional(()ExtParam); break; // Запуск расчета case : if((()ExtParam)->FirstStart) data->AllocateArrays(); // Первый запуск break; // Сброс расчета case : data->ClearArrays(); break; // Реакция на изменение динамической переменной case : data->AddPoint(x); break; } return ; // Отмена макроопределений для переменных #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=; // Диапазоны осей, шаг сетки, число десятичных знаков // в числах на осях 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=( , // В родительской подсистеме "DynTime", // Имя переменной "D", // Тип переменной (double) TRUE); // Искать по иерархии } //========================================= // Деструктор класса TSimplePlotData::~TSimplePlotData() { (Time); // Прекратить подписку ClearArrays(); // Освободить массивы } //========================================= // Рисование внешнего вида блока void TSimplePlotData::Draw( DrawData) { // Вспомогательные переменные // int Gr_x1,Gr_x2,Gr_y1,Gr_y2; - эти переменные стали полями класса int x1,y1,x2,y2,textheight,w1,w2; char buf[80]; // Рамка графика (0,,1,BorderColor,); (0,,FillColor); (DrawData->Left,DrawData->Top, DrawData->Left+DrawData->Width, DrawData->Top+DrawData->Height); // Необходимо вычислить координаты поля графика относительно // верхнего левого угла блока // Установка параметров шрифта с учетом масштаба (&Font,DrawData->DoubleZoom); ("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); (buf,&w1,NULL); // Ширина Ymin sprintf(buf," %.*lf ",YNumDecimal,Ymax); (buf,&w2,NULL); // Ширина Ymax if(w2>w1) w1=w2; sprintf(buf," %.*lf ",XNumDecimal,Xmin); (buf,&w2,NULL); // Ширина Xmin w2/=2; if(w2>w1) w1=w2; Gr_x1=w1; // Зазор справа – половина ширины Xmax sprintf(buf," %.*lf ",XNumDecimal,Xmax); (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; // Прямоугольник поля графика (0,,1,PlotBorderColor,); (0,,PlotFillColor); (x1,y1,x2,y2); // Установка пунктирного стиля линии (0,,1,PlotBorderColor,); (0,,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) // Чертим вертикальную линию { (ix,y1); (ix,y2); } // Вывод числа на оси под полем sprintf(buf,"%.*lf",XNumDecimal,x); (buf,&w1,NULL); (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) // Чертим горизонтальную линию { (x1,iy); (x2,iy); } // Вывод числа на оси слева от поля sprintf(buf,"%.*lf ",YNumDecimal,y); (buf,&w1,&textheight); (x1-w1-2,iy-textheight/2,buf); } // Если массивы не пустые – рисовать график if(Count) { r; // Установить область отсечения рисования по полю графика r.left=x1+1; r.top=y1+1; r.right=x2-1; r.bottom=y2-1; (&r); // Установить сплошной стиль линии, заданный для // графика цвет и толщину линии с учетом масштаба (0,, LineWidth*DrawData->DoubleZoom, LineColor,); // Строим ломанную линию по отсчетам из массивов 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) // Не первая точка – строим линию от предыдущей (ix,iy); else // Первая точка графика – делаем ее текущей (ix,iy); } // Запоминаем последний нарисованный отсчет LastDrawnIndex=NextIndex-1; // Отмена отсечения (NULL); } } //========================================= // Рисование изменений void TSimplePlotData::DrawFast( 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) { r; // Установить область отсечения рисования по полю графика r.left=x1+1; r.top=y1+1; r.right=x2-1; r.bottom=y2-1; (&r); // Установить сплошной стиль линии, заданный для // графика цвет и толщину линии с учетом масштаба (0,, LineWidth*DrawData->DoubleZoom, LineColor,); // Проверка допустимости 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) (ix,iy); else (ix,iy); } // Запоминаем последний нарисованный отсчет LastDrawnIndex=NextIndex-1; // Отмена отсечения (NULL); } } //========================================= // Дополнительное рисование void TSimplePlotData::DrawAdditional( DrawData) { // Проверка доступа к переменной времени if(Time==NULL || Time->Data==NULL) // Доступа нет { int w,h; // Константа, указывающая на стандартную иконку RDS DWORD icon=; // Определяем размер иконки и выводим ее в центре блока if((icon,&w,&h)) (DrawData->Left+(DrawData->Width-w)/2, DrawData->Top+(DrawData->Height-h)/2, icon); } } //========================================= // Отведение памяти под массивы 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) { ini; char *str; // Создание объекта для работы с текстом ini=(TRUE); // Создание в тексте секции "[General]" (ini,,0,"General"); // Запись в секцию различных параметров (ini,"TimeStep",TimeStep); (ini,"Xmin",Xmin); (ini,"Xmax",Xmax); (ini,"XGridStep",XGridStep); (ini,"XNumDecimal",XNumDecimal); (ini,"Ymin",Ymin); (ini,"Ymax",Ymax); (ini,"YGridStep",YGridStep); (ini,"YNumDecimal",YNumDecimal); // Создание в тексте секции "[Visuals]" (ini,,0,"Visuals"); // Запись в секцию различных параметров (ini,"BorderColor",(int)BorderColor); (ini,"FillColor",(int)FillColor); (ini,"PlotBorderColor",(int)PlotBorderColor); (ini,"PlotFillColor",(int)PlotFillColor); (ini,"LineColor",(int)LineColor); (ini,"LineWidth",LineWidth); // Преобразование описания шрифта в строку для сохранения str=(&Font,NULL); // Запись строки с описанием шрифта (ini,"Font",str); (str); // Освобождение памяти, занятой строкой // Запись сформированного текста в файл схемы или буфер обмена (ini,); // Уничтожение вспомогательного объекта (ini); } //========================================= // Загрузка параметров в текстовом виде из строки text void TSimplePlotData::LoadText(char *text) { ini; char *str; // Создание объекта для работы с текстом ini=(TRUE); // Загрузка текста в объект (ini,,0,text); // Если в тексте есть секция "General", загрузить из нее данные if((ini,"General")) { TimeStep=(ini,"TimeStep",TimeStep); Xmin=(ini,"Xmin",Xmin); Xmax=(ini,"Xmax",Xmax); XGridStep=(ini,"XGridStep",XGridStep); XNumDecimal=(ini,"XNumDecimal",XNumDecimal); Ymin=(ini,"Ymin",Ymin); Ymax=(ini,"Ymax",Ymax); YGridStep=(ini,"YGridStep",YGridStep); YNumDecimal=(ini,"YNumDecimal",YNumDecimal); } // Если в тексте есть секция "Visuals", загрузить из нее данные if((ini,"Visuals")) { BorderColor=()(ini,"BorderColor", (int)BorderColor); FillColor=()(ini,"FillColor", (int)FillColor); PlotBorderColor=()(ini, "PlotBorderColor",(int)PlotBorderColor); PlotFillColor=()(ini,"PlotFillColor", (int)PlotFillColor); LineColor=()(ini,"LineColor", (int)LineColor); LineWidth=()(ini,"LineWidth",LineWidth); str=(ini,"Font","",NULL); if(str) (str,NULL,&Font); } // Уничтожение вспомогательного объекта (ini); } //========================================= // Функция настройки параметров блока // // // int TSimplePlotData::Setup(void) { window; ok; char *str; // Создание окна window=(TRUE,-1,-1,"Простой график"); // Вкладка "Оси" (window,1,"Оси"); (window,1,100, | ,"Шаг записи",50); (window,100,,TimeStep); // Текстовая метка без возможности ввода (window,1,1,,"Ось X:",0); // Диапазон (два поля ввода в одной строке) (window,1,2,,"Диапазон",90); (window,2,,Xmin); (window,2,,Xmax); (window,1,3,,"Шаг сетки",50); (window,3,,XGridStep); // Поле ввода со стрелками увеличения/уменьшения (window,1,4, | , "Дробная часть чисел",50); (window,4,,XNumDecimal); (window,4,,0); (window,4,,5); (window,4,,1); // Текстовая метка без возможности ввода (window,1,5,,"Ось Y:",0); (window,1,6,,"Диапазон",90); (window,6,,Ymin); (window,6,,Ymax); (window,1,7,,"Шаг сетки",50); (window,7,,YGridStep); (window,1,8,, "Дробная часть чисел",50); (window,8,,YNumDecimal); (window,8,,0); (window,8,,5); (window,8,,1); // Вкладка "Внешний вид" (window,2,"Внешний вид"); (window,2,9,,"Цвет рамки блока",50); (window,9,,(int)BorderColor); (window,2,10, | ,"Цвет фона блока",50); (window,10,,(int)FillColor); (window,2,11,,"Цвет рамки графика и сетки",50); (window,11,,(int)PlotBorderColor); (window,2,12,,"Цвет фона графика",50); (window,12,,(int)PlotFillColor); (window,2,13,,"Цвет линии графика",50); (window,13,,(int)LineColor); (window,2,14, | , "Толщина линии графика",50); (window,14,,LineWidth); (window,14,,0); (window,14,,5); (window,14,,1); // Кнопка открытия диалога выбора шрифта (window,2,15,,"Шрифт чисел",0); // Преобразование шрифта в строку и занесение в поле ввода str=(&Font,NULL); (window,15,,str); (str); // Открытие окна ok=(window,NULL); if(ok) { // Нажата кнопка OK - запись параметров обратно в блок Xmin=(window,2,); Xmax=(window,2,); XGridStep=(window,3,); XNumDecimal=(window,4,); TimeStep=(window,100,); Ymin=(window,6,); Ymax=(window,6,); YGridStep=(window,7,); YNumDecimal=(window,8,); BorderColor=()(window,9,); FillColor=()(window,10,); PlotBorderColor=()(window,11,); PlotFillColor=()(window,12,); LineColor=()(window,13,); LineWidth=(window,14,); // Получение параметров шрифта из строки str=(window,15,); (str,NULL,&Font); } // Уничтожение окна (window); // Возвращаемое значение return ok?:; } //=========================================
/* // Поиск отсчета, соответствующего времени t // (линейный поиск) int TSimplePlotData::FindTimeIndex(double t) { if(Count==0) // Массивы пусты return -1; if(t<=Times[0]) // t раньше начала массива return 0; // Ближайший индекс - 0 // Поиск первого индекса, большего t for(int i=1;i<NextIndex;i++) if(Times[i]>t) // t между i-1 и i { double d1=fabs(t-Times[i-1]), d2=fabs(t-Times[i]); return (d1<d2)?(i-1):i; // Возвращаем ближайший } // Ничего не нашли – значит, t>Times[NextIndex-1] return NextIndex-1; } //========================================= */
// Поиск отсчета, соответствующего времени t // (метод деления пополам) int TSimplePlotData::FindTimeIndex(double t) { int L,R; double dl,dr; if(Count==0 || NextIndex==0) // Нет данных в массивах return -1; if(NextIndex==1) // В массиве единственный отсчет return 0; // В массиве по крайней мере два значения – проверяем границы if(t<=Times[0]) // t меньше первого отсчета return 0; if(t>=Times[NextIndex-1]) // t больше последнего отсчета return NextIndex-1; // t - внутри диапазона массива L=0; R=NextIndex-1; while(L<R-1) { int m=(L+R)/2; if(Times[m]<t) L=m; else R=m; } // t лежит между L и R dl=fabs(t-Times[L]), dr=fabs(t-Times[R]); return (dl<dr)?L:R; // Возвращаем ближайший } //=========================================
// Всплывающая подсказка // // // void TSimplePlotData::PopupHint( hintdata) { int x1,x2,y1,y2,index; double t; char *text,*str_t,*str_v; // Проверка доступа к переменной времени if(Time==NULL || Time->Data==NULL) { ("ОШИБКА: в схеме нет переменной DynTime"); return; } // Определение абсолютных координат поля графика x1=hintdata->Left+Gr_x1; x2=hintdata->Left+Gr_x2; y1=hintdata->Top+Gr_y1; y2=hintdata->Top+Gr_y2; // Если курсор мыши не попадает в поле графика, // подсказку выводить не нужно if(hintdata->x<x1 || hintdata->x>x2 || hintdata->y<y1 || hintdata->y>y2) return; // Преобразование экранной горизонтальной координаты // в значение времени согласно масштабу графика t=(hintdata->x-x1)*(Xmax-Xmin)/(x2-x1)+Xmin; // Поиск отсчета, соответствующего этому моменту времени index=FindTimeIndex(t); if(index<0) return; // Ошибка – отчет не найден // Преобразование времени и значения отсчета в строки str_t=(Times[index],-1,NULL); str_v=(Values[index],-1,NULL); // Формирование текста подсказки text=("Время: ",str_t,FALSE); (&text,"\nЗначение: ",FALSE); (&text,str_v,FALSE); // Установка текста подсказки (text); // Освобождение динамических строк (text); (str_t); (str_v); // Изменение параметров подсказки таким образом, чтобы при // смещении курсора на одну точку она вывелась снова hintdata->HZLeft=hintdata->x; hintdata->HZTop=hintdata->y; hintdata->HZWidth=hintdata->HZHeight=1; // Задержка гашения подсказки – одна минута hintdata->HideTimeout=60000; } //=========================================


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