Страницы

понедельник, 9 декабря 2013 г.

Печать нрафика C++

График - вывод массива на печать (BDS 2006, C++)

Иногда в заданиях требуется выводить какие-либо данные в виде графика. В этом посте рассмотрим графическую часть подобной задачи.

Программа для печати графика

Формирование массива сделаем так же, как и в предыдущем варианте (печать столбиковой диаграммы).
Все элементы на форме оставляем прежними (сетка строк sg, кнопки «Новый массив» - btnNew, «Закрыть» - btnClose, рисунок im). Я не буду повторяться, поскольку все точно так же. Изменим лишь одну функцию ShowArray():

void ShowArray()
{
    int wIm = frmMain->im->Width;  //ширина рисунка
    int hIm = frmMain->im->Height; //высота рисунка
    int x, h, hCol, wCol, i;
    //рисуем рамку
    frmMain->im->Canvas->Brush->Color = (TColor)RGB(255,255,255);
    frmMain->im->Canvas->Rectangle(0,0,wIm, hIm);
    //Заголовок
    frmMain->im->Canvas->Font->Name = "Tahoma";
    frmMain->im->Canvas->Font->Size = 13;
    //выводим посередине рисунка
    x = (frmMain->im->Width - frmMain->Canvas->TextWidth(title))/2;
    frmMain->im->Canvas->Brush->Style = bsClear;
    frmMain->im->Canvas->TextOutA(x,10,title);
    frmMain->im->Canvas->Font->Style = TFontStyles()<<fsBold;
    wCol = int((frmMain->im->Width-10)/arSize);  //определяем расстояние между точками по горизонтали
    x = 10;                                //позиция по горизонтали
    int min, max;       //максимальный и минимальный эелемент массива
    min = 0;            //принимаем за минимальный - первый элемент
    max = 0;            //принимаем за максимальный - первый элемент
    for(i = 1; i<arSize; i++)
    {
        if (data[i] < data[min]) {
            min = i;  //если следующий меньше предыдущего, то он //минимальный
        }
        if (data[i]>data[max]) {
            max = i;             //так же с максимальным элементом
        }
    }
    hCol = (frmMain->im->ClientHeight - 90)/data[max];   //коэффициент для расчета ординаты точки
        for (i = 0; i < arSize; i++) {
        h = hCol*data[i];       //высота, на которой выводим надпись
        frmMain->im->Canvas->TextOutA(x-2,hIm-h-40, IntToStr(data[i]));
        x+=wCol;
        }
        x = 15;
    for (i = 0; i < arSize; i++) {
        h = hCol*data[i];                       //высота точки
       //
        if (i) {
            frmMain->im->Canvas->LineTo(x,hIm-h); //проводим линию
        }
        frmMain->im->Canvas->Ellipse(x-2,hIm-h-2,x+2,hIm-h+2);  //рисуем точку
        frmMain->im->Canvas->MoveTo(x,hIm-h);
        x+=wCol;
    }
}
Сначала нарисуем рамку вокруг рисунка с помощью функции «Прямоугольник» Canvas->Rectangle(0,0,wIm, hIm). Размеры соответствуют размерам элемента формы im.
Затем устанавливаем название и размер шрифта и посередине рисунка выводим заголовок графика. Значения точек будем выводить жирным шрифтом, поэтому устанавливаем этот стиль шрифта с помощью свойства Style. Canvas->Font->Style = TFontStyles()<<fsBold.

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

После подсчета значений коэффициентов в цикле выводим подпись каждой точки. Далее еще в одном цикле начинаем выводить сами точки в виде кружков (Ellipse), соединяя их линиями (LineTo), причем линию рисуем, если данная точка не первая. Для возврата в точку после рисования кружка необходимо использовать функцию MоveTo.
В общем, это все несложно пока. При реальном применении все гораздо сложнее.