API и FreeBasic. (Рисование с помощью GDI - контексты)

По поводу рисования с помощью GDI написана куча книг. И если вы всерьез хотите изучить все тонкости этой подсистемы, то наверное лучше поискать книгу, написанную проффесионалом. Я же ставлю цель описать основные принципы и только часто используемое.

Принцип рисования прост:

  1. Получаем или создаем контекст отображения\устройства.
  2. Рисуем (при этом есть возможность изменять различные атрибуты в контексте) 
  3. Освобождаем\удаляем контекст устройства

Отсюда, для получения контекста отображения и вообще рисования, можно использовать блоки:

BeginPaint(hwnd,LPPAINTSTRUCT)
' рисуем
EndPaint(hwnd,LPPAINTSTRUCT)

hdc = GetDC(hwnd)
' рисуем
ReleaseDC(hwnd,hdc)

hdc = GetWindowDC(hwnd)
' рисуем
ReleaseDC(hwnd,hdc)

Первый блок используется только в оконной процедуре в сообщении WM_PAINT. При том информация (контекст отображения, прямоугольник вывода рисуемой части) находится в структуре PAINTSTRUCT. Перед вызовом функции BeginPaint , нужно создать переменную на базе типа PAINTSTRUCT и отправить указатель на нее во второй параметр функций BeginPaint, EndPaint. Система заполнит структуру нужными данными при вызове BeginPaint. Сама структура PAINTSTRUCT выглядит так:

Type PAINTSTRUCT
    hdc As HDC 'контекст отображения
    fErase As BOOL 'флаг перерисовки фона
    rcPaint As RECT 'структура ограничивающего прямоугольника для рисования
    fRestore As BOOL 'не используется
    fIncUpdate As BOOL 'не используется
    rgbReserved(0 To 32-1) As Ubyte 'не используется
End Type

Второй и третий блоки получения контекста можно использовать в любом месте программы. При том, два первых блока рисуют в клиентской области окна, третий блок может рисовать в любой части окна. 

Примечание:  GetWindowDc в системе Windows Xp работает как заявлено. В системе Windows 7 , при установке стандартной схемы Windows 7, GetWindowDc  рисует на всем окне только в сообщении WM_NCPAINT. Если его использовать в любых других местах программы, то рисование происходит только в клиентской области окна, хотя координаты учитываются со всего окна.

Для создания контекста устройства используют такой блок:

hdc = CreateDC(lpszDrive, lpszDevice , lpszOutput, lpInitData)
' рисуем
deletedc(hdc)

lpszDriver - имя драйвера
lpszDevice - имя устройства
lpszOutput - имя файла или порта вывода
lpInitData - данные для инициализации

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

Есть и так называемый совместимый контекст устройства, создаваемый в памяти, на основе имеющегося контекста отображения. Его используют для рисования битовых изображений в памяти с последующим выводом на экран. Такой вариант часто оказывается быстрее, чем прямой вывод на экран. Кроме того, помогает приложению избавиться от мерцания при выводе. Общая схема работы выглядит примерно так:

hdc = GetDC(hwnd)
hdcMem = CreateCompatibleDC(hdc)
bitmap = CreateCompatibleBitmap(dc,x,y)
SelectObject(hdcMem,bitmap)
'
' рисуем
' 
' копируем из hdcMem в hdc с 
' помощью BitBlt или StretchBlt 
'
DeleteObject(bitmap)
DeleteDc(hdcMem)
ReleaseDC(hwnd,hdc)

В любом случае создаете или получаете контекст, его всегда следует освобождать (когда отпадает в нем надобность) во избежания утечек памяти! Хотя надо сказать, что я сам бывало забывал делать это :)

Вообще это не все возможные реализации создания\получения контекстов, есть и другие, но они почти не используются.

И уж раз упоминал в блоке такие функции как BitBlt и StretchBlt, то стоит сказать, что разница между ними в том, что вторая позволяет масштабировать изображение при копировании. 

Декларация этих функций выглядит следующим образом:

BitBlt( _
  hdcDest As Integer,_       'контекст куда копировать
  nXDest As Integer,_        'x-координата верхнего левого угла области куда копировать
  nYDest As Integer,_        'y-координата верхнего левого угла области куда копировать
  nWidthDest As Integer,_    'ширина изображения
  nHeightDest As Integer,_   'высота изображения
  hdcSrc As HDC,_            'контекст откуда копировать
  nXSrc As Integer,_         'x-координата верхнего левого угла копируемой области
  nYSrc As Integer,_         'y-координата верхнего левого угла копируемой области
  dwRop As Integer _         'код растровой операции
  ) As BOOL  

StretchBlt( _
  hdcDest As Integer,_       'контекст куда копировать
  nXDest As Integer,_        'x-координата верхнего левого угла области куда копировать
  nYDest As Integer,_        'y-координата верхнего левого угла области куда копировать
  nWidthDest As Integer,_    'новая ширина изображения
  nHeightDest As Integer,_   'новая высота изображения
  hdcSrc As HDC,_            'контекст откуда копировать
  nXSrc As Integer,_         'x-координата верхнего левого угла копируемой области
  nYSrc As Integer,_         'y-координата верхнего левого угла копируемой области
  nWidthSrc As Integer,_     'ширина исходного изображения
  nHeightSrc As Integer,_    'высота исходного изображения
  dwRop As Integer _         'код растровой операции
  ) As BOOL

Ну вот пожалуй и все про контексты.

содержание | назад | вперед