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

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

  // Программное рисование - индикатор уровня и простой график
  #include <windows.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;
  }
  //========= Конец главной функции =========

  //=========== Индикатор уровня ============
  // Прототип функции рисования
  void SimpleLevelIndicatorDraw( draw,double val);

  // Модель простого индикатора уровня
  extern "C" __declspec(dllexport) int  SimpleLevelIndicator(
        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)))

    switch(CallMode)
      { // Проверка допустимости типа переменных
        case :
          if(strcmp((char*)ExtParam,"{SSD}"))
            return ;
          return ;

        // Рисование внешнего вида блока
        case :
          SimpleLevelIndicatorDraw(()ExtParam,x);
          break;
      }
    return ;
  // Отмена макроопределений
  #undef x
  #undef Ready
  #undef Start
  #undef pStart
  }
  //=========================================

  // Функция рисования простого индикатора уровня
  void SimpleLevelIndicatorDraw( draw,double val)
  { // Диапазон допустимых значений входа
    const double Min=0.0,Max=100.0;
    // Цвета индикатора
    const  empty=0xffffff, // Верхняя часть (белый)
                   fill=0xff0000,  // Нижняя часть (синий)
                   border=0;       // Рамка вокруг (черный)
    // Вспомогательные переменные
    int height,fullheight,x1,y1,x2,y2;

    // Координаты прямоугольника внутри рамки (отступ в 1 точку)
    x1=draw->Left+1;
    y1=draw->Top+1;
    x2=draw->Left+draw->Width-1;
    y2=draw->Top+draw->Height-1;
    // Выстота блока без толщины рамки (==draw->Height-2)
    fullheight=(y2-y1);

    // Высота столбика (от нижней границы до линии раздела)
    height=(val-Min)*fullheight/(Max-Min);
    // Ограничения сверху и снизу
    if(height>fullheight)
      height=fullheight;
    else if(height<0)
      height=0;

    // Рисование рамки
    (0,,1,border,);
    (0,,0);
    (draw->Left,draw->Top,
                   draw->Left+draw->Width,draw->Top+draw->Height);
    // Закраска верхней части цветом empty
    if(height!=fullheight)
      { (0,,empty);
        (x1,y1,x2,y2-height);
      }
    // Закраска нижней части цветом fill
    if(height!=0)
      { (0,,fill);
        (x1,y2-height,x2,y2);
      }
  }
  //=========================================



  //=========================================
  // Простой график – личная область данных
  //=========================================
  class TSimplePlotData
  { private:
      // Настроечные параметры графика (цвета, шаг и т.п.)
      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 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  SimplePlot(
        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)))
    // Указатель на личную область, приведенный к правильному типу
    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 :
          return data->Setup();

        // Загрузка параметров в текстовом формате
        case :
          data->LoadText((char*)ExtParam);
          break;

        // Созранение параметров в текстовом формате
        case :
          data->SaveText();
          break;

        // Рисование внешнего вида блока
        case :
          data->Draw(()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)
  { // Присвоение начальных значений параметрам
    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);
    // Зазор сверху – половина высоты цифры + 1 точка
    ("0",NULL,&textheight);
    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;

    // Абсолютные (на рабочем поле) координаты поля графика
    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);
          }

        // Отмена отсечения
        (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)
  {  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?:;
  }
  //=========================================


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