Графика в оконных приложениях : точка, перо, кисть, фон

Графика в оконных приложениях

Для рисования графических примитивов в оконных приложениях используются 4 основных типа объектов:
  • точка (Pixel);
  • перо (Pen);
  • кисть (Brush);
  • фон (Background).

Точка

Цвет точки задается с помощью функции

 
 
 
 
 
COLORREF SetPixel(
_In_  HDC hdc,   // дескриптор контекста устройства
_In_  int X,    // x-координата точки
_In_  int Y,   // y-координата точки
_In_  COLORREF crColor ); // цвет точки

В случае удачного завершения возвращаемое значение функции дублирует цвет точки, в случае ошибки возвращает -1.

Цвет точки представляет собой 32-битное число, заданное в системе RGB:

RGB

Можно также воспользоваться функцией

 
 
 
 
RGB(
_ Red As Integer,  // красный
_ Green As Integer,  // зеленый
_ Blue As Integer);  // синий

Значения красного, зеленого и синего используются в диапазоне 0…255.

Перо

Перо используется для рисования линий и контуров замкнутых фигур. Цвет пера задается функцией

 
 
 
 
HPEN CreatePen(
_In_  int fnPenStyle,      // стиль пера
_In_  int nWidth,      // ширина пера (в пикселях)
_In_  COLORREF crColor );  // цвет пера

Стили пера fnPenStyle могут быть заданы согласно таблице

Значение Тип Описание
PS_SOLID 0 PS_SOLID Сплошное перо
PS_DASH 1 PS_DASH Прерывистое (пунктирное) перо
PS_DOT 2 PS_DOT Точечное (штриховое) перо
PS_DASHDOT 3 PS_DASHDOT Штрих-пунктир
PS_DASHDOTDOT 4 PS_DASHDOTDOT Две точки — пунктир
PS_NULL 5 Невидимое перо
При успешном завершении функция возвращает дескриптор пера, в случае неудачи — константу NULL.

Кисть

Кисть используется для закрашивания замкнутых объектов. Цвет кисти задается с помощью функции

 
 
HBRUSH CreateSolidBrush(
_In_  COLORREF crColor );   // цвет кисти

При успешном завершении функция возвращает дескриптор кисти, в случае неудачи — константу NULL. Эта же функция используется для задания цвета фона.

Можно заранее создать несколько кистей и перьев, а затем выбирать нужные с помощью функции

 
 
 
HGDIOBJ SelectObject(
_In_  HDC hdc,      // дескриптор контекста устройства
_In_  HGDIOBJ hgdiobj );     // дескриптор объекта

Рисование графических примитивов

Перемещение в указанную точку осуществляется функцией:

 
 
 
 
 
BOOL MoveToEx(
_In_   HDC hdc,    // дескриптор контекста устройства
_In_   int X,  // координата x точки
_In_   int Y,    // координата y точки
_Out_  LPPOINT lpPoint );   // указатель на структуру POINT

Координаты точки x и у определяются в пикселях относительно левого верхнего угла. В случае успешного выполнения возвращает ненулевое значение.

Структура POINT имеет вид

 
 
 
typedef struct tagPOINT {
LONG x;
LONG y; } POINT, *PPOINT;

Рисование отрезков осуществляется функцией:

 
 
 
 
BOOL LineTo(
_In_  HDC hdc,       // дескриптор контекста устройства
_In_  int nXEnd,    // координата x конечной точки
_In_  int nYEnd );   // координата y конечной точки

В случае успешного выполнения возвращает ненулевое значение.

Рисование прямоугольника осуществляется функцией:

 
 
 
 
 
 
BOOL Rectangle(
_In_  HDC hdc,           // дескриптор контекста устройства
_In_  int nLeftRect,     // x-координата верхнего левого угла
_In_  int nTopRect,      // y-координата верхнего левого угла
_In_  int nRightRect,    // x-координата нижнего правого угла
_In_  int nBottomRect);    // координата нижнего правого угла

Рисование прямоугольника начинается из точки, в которую осуществлено перемещение с помощью функции MoveTo(). В случае успешного выполнения возвращает ненулевое значение.

Рисование эллипса осуществляется функцией:

 
 
 
 
 
 
BOOL Ellipse(
_In_  HDC hdc,           // дескриптор контекста устройства
_In_  int nLeftRect,     // x-координата верхнего левого угла
_In_  int nTopRect,      // y-координата верхнего левого угла
_In_  int nRightRect,    // x-координата нижнего правого угла
_In_  int nBottomRect);    // координата нижнего правого угла
Овал

В случае успешного выполнения возвращает ненулевое значение.

Рисование дуги осуществляется функцией:

 
 
 
 
 
 
 
 
 
 
BOOL ArcTo(
_In_  HDC hdc,   // дескриптор контекста устройства
_In_  int nLeftRect,   // x-координата верхнего левого угла
_In_  int nTopRect,   // y-координата верхнего левого угла
_In_  int nRightRect,  // x-координата нижнего правого угла
_In_  int nBottomRect,   // y-координата нижнего правого угла
_In_  int nXRadial1,   // x- координата конца первого радиуса
_In_  int nYRadial1,   // y- координата конца первого радиуса
_In_  int nXRadial2,   // x- координата конца второго радиуса
_In_  int nYRadial2 );   // y- координата конца второго радиуса
Дуга

В случае успешного выполнения возвращает ненулевое значение.

Вывод текста в окно

Для вывода текста в поле окна используется функция

 
 
 
 
 
 
BOOL TextOut(
_In_  HDC hdc,   // дескриптор контекста устройства
_In_  int nXStart,    // x-координата начала вывода текста
_In_  int nYStart,   // y-координата начала вывода текста
_In_  LPCTSTR lpString,  // указатель на строку текста
_In_  int cchString );  // количество символов для вывода

В случае успешного выполнения возвращает ненулевое значение.

Задать цвет фона под буквами можно с помощью функции

 
 
 
COLORREF SetBkColor(
_In_  HDC hdc,   // дескриптор контекста устройства
_In_  COLORREF crColor );    // цвет

Задать цвет букв можно с помощью функции

 
 
 
COLORREF SetЕTextColor(
_In_  HDC hdc,   // дескриптор контекста устройства
_In_  COLORREF crColor );    // цвет

В случае неудачного завершения эти функции возвращают константу CLR_INVALID=0xFFFF.

Использование графических функций

Для перерисовки окна, в котором будут отображаться графические объекты, будем использовать обработку сообщения WM_PAINT.

Обработка сообщения WM_PAINT почти всегда начинается с вызова функции:

 
 
 
HDC BeginPaint(
_In_   HWND hwnd,
_Out_  LPPAINTSTRUCT lpPaint );

При обработке вызова BeginPaint(), Windows обновляет фон рабочей области с помощью кисти, заданной в поле hbrBackground структуры WNDCLASS, описанной здесь. Вызов BeginPaint() делает всю рабочую область действительной (не требующей перерисовки) и возвращает описатель контекста устройства. Контекст устройства описывает физическое устройство вывода информации (например, экран) и его драйвер. Описатель контекста устройства необходим для вывода в рабочую область окна текста и графики.

Аргументы функции:

  • hwnd – дескриптор окна;
  • lpPaint – указатель на структуру PAINTSTRUCT.

Структура PAINTSTRUCT имеет вид

 
 
 
 
 
 
 
typedef struct tagPAINTSTRUCT {
HDC  hdc;
BOOL fErase;
RECT rcPaint;
BOOL fRestore;
BOOL fIncUpdate;
BYTE rgbReserved[32]; } PAINTSTRUCT, *PPAINTSTRUCT;

Члены структуры:

  • hdc – дескриптор контекста устройства.
  • fErase – ненулевое значение стирает фон.
  • rcPaint – структура RECT, определяющая верхний левый и нижний правый углы рабочей области.
     
     
     
    typedef struct _RECT {
    LONG left; LONG top;
    LONG right; LONG bottom; } RECT, *PRECT;
  • fRestore, fIncUpdate, rgbReserved  – зарезервировано, используется системой.

Обработка сообщения WM_PAINT почти всегда заканчивается вызовом функции:

 
 
 
BOOL EndPaint(
_In_  HWND hWnd,
_In_  const PAINTSTRUCT *lpPaint );

Функция EndPaint() освобождает описатель контекста устройства, после чего его значение нельзя использовать. Возвращает всегда ненулевое значение.

Получение дескриптора контекста устройства осуществляется вызовом функции:

 
HDC GetDC(_In_  HWND hWnd);

hWnd – дескриптор окна, для которого используется контекст устройства. Возвращаемое значение – дескриптор контекста устройства.

Функция

 
 
 
int ReleaseDC(
_In_  HWND hWnd,
_In_  HDC hDC );

освобождает контекст устройства hDC для данного окна hWnd, после чего значение контекста устройства нельзя использовать. Возвращает всегда ненулевое значение.

3 комментария к “Графика в оконных приложениях”

  1. Артем

    Прошу прощения. Может я что-то не увидел, но какую библиотеку надо подключить?

  2. Здравствуйте, Елена, спасибо за Ваш сайт, много интересного.
    По поводу графики отмечу, что было бы хорошо, если бы здесь было бы упоминание про двойную буферизацию (это помогает избавиться от эффектов мерцания, если такие наблюдаются при рисовании). Вот часть кода из моей программы.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
    {
        switch (message)
        {
        //…
        case WM_PAINT:
            PaintAll(hwnd);
            return 0;
        case WM_ERASEBKGND:
            return 0;
        //…
        }
        return DefWindowProc(hwnd, message, wparam, lparam);
    }

    namespace e
    {
        extern HWND hpicturebox; // это окно где что-то рисуется
    }

    void PaintAll(HWND hwnd)
    {
        HDC hdc, hcmpdc;
        HBITMAP hbmp;
        HBRUSH hbrush;
        HPEN hpen;
        PAINTSTRUCT ps;
        RECT rect;
        BeginPaint(hwnd, &ps); // здесь hwnd окна на котором расположен hpicturebox
        EndPaint(hwnd, &ps);
        GetClientRect(e::hpicturebox, &rect);
        hdc = GetDC(e::hpicturebox);
        hcmpdc = CreateCompatibleDC(hdc);
        hbmp = CreateCompatibleBitmap(hdc, rect.right — rect.left, rect.bottom — rect.top);
        hbrush = CreateSolidBrush(RGB(255, 255, 255));
        hpen = CreatePen(PS_INSIDEFRAME, 1, RGB(255, 255, 255));
        BeginPaint(e::hpicturebox, &ps);
        SelectObject(hcmpdc, hbmp);
        SelectObject(hcmpdc, hbrush);
        SelectObject(hcmpdc, hpen);
        Rectangle(hcmpdc, rect.left, rect.top, rect.right, rect.bottom);
        //
        PaintPicturebox(hcmpdc); // <—— здесь ваше рисование
        //
        SetStretchBltMode(hdc, COLORONCOLOR);
        BitBlt(hdc, 0, 0, rect.right — rect.left, rect.bottom — rect.top, hcmpdc, 0, 0, SRCCOPY);
        EndPaint(e::hpicturebox, &ps);
        ReleaseDC(e::hpicturebox, hdc);
        DeleteDC(hcmpdc);
        DeleteObject(hbmp);
        DeleteObject(hbrush);
        DeleteObject(hpen);
    }

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Прокрутить вверх