API и FreeBasic. (Пpостой битмэп)
На этом уроке мы научимся использовать битмэпы в своих программах. Если быть более точным, мы научимся отображать битмэп в клиентской области нашей программы.
Битмэпы можно представлять себе как изображения, хранимые в компьютере. На компьютерах используется множество различных форматов изображений, но Windows естественным образом поддерживает только формат растровых изображений Windows (.bmр). На этом уроке, когда речь будет идти о битмэпах, будет подразумеваться именно этот формат. Самый простой способ использовать битмэп - это использовать его как ресурс. Есть два способа это выполнить. Можно включить битмэп в файл определения ресурсов (.rc) следующим образом:
#define IDB_MYBITMAp 100 IDB_MYBITMAp BITMAp "c:\project\example.bmp"
В этом методе для представления битмэпа используется константа. В первой строчке просто задаётся константа с именем IDB_MYBITMAp и значением 100. По этому имени мы и будем обращаться к битмэпу в нашей программе. В следующей строке объявляется битмэп-ресурс. Таким образом, компилятор узнаёт, где ему искать собственно сам .bmp файл.
В другом методе для представления битмэпа используется имя, делается это следующим образом:
MyBitMap BITMAp "c:\project\example.bmp"
При использовании этого метода, в вашей программе вам придётся ссылаться на битмэп по строке "MyBitMaр", а не по значению.
Оба метода прекрасно работают, главное - определиться, какой именно вы будете использовать. После включения битмэпа в файл ресурсов, можно приступить к его отображению в клиентской области нашего окна:
- Вызовите LoadBitmap чтобы узнать хэндл битмэпа. Функция LoadBitmaр имеет
следующий прототип:
LoadBitmap (hInstance As HINSTANCE, l?Bitma?Name As LPCSTR) As HBITMAP
- Функция возвращает хэндл битмэпа. hInstance есть хэндл инстанции вашей
программы. lрBitmaрName - это указатель на строку, содержащую имя битмэпа
(необходимо при использовании 2-го метода). Если для обращения к битмэпу вы
используете константу (например, IDB_MYBITMAр), то её значение вы и должны
сюда поместить (в нашем случае это было бы значение 100). Не помешает
небольшой пример:
- Первый метод:
IDB_MYBITMAp equ 100 .... hInstance = GetModuleHandle(NULL) .... hBitmap = LoadBitmap(hInstance, Cast(lpstr, IDB_MYBITMAp))
- Второй метод:
hInstance = GetModuleHandle(NULL) .... hBitmap = LoadBitmap(hInstance,Strptr("MyBitMap"))
- Первый метод:
- Получите хэндл device context'a (DC). Это можно сделать либо вызовом
функции Beginpaint в ответ на сообщение WM_pAINT, либо вызовом GetDC в любое
время.
Создайте device context в памяти (memory DC) с теми же аттрибутами, что и device context, полученный на предыдущем шаге. Идея в том, чтобы создать некоторую "невидимую" поверхность, на которой мы можем отрисовать битмэп. После этого мы просто копируем содержимое невидимой поверхности в текущий device context с помощью вызова одной-единственной функции. Этот приём называется двойной буферизацией (double buffering) и используется для быстрого вывода изображений на экран. Создать "невидимую" поверхность можно вызовом CreateCompatibleDC:
CreateCompatibleDC(hdc As HDC) As HDC
При успешном завершении функция возвращает через регистр eax хэндл device context'a в памяти. hdc - это хэндл device context'a, с которым должен быть совместим DC в памяти.
- После создания невидимой поверхности вы можете отобразить на ней битмэп с
помощью вызова SelectObject, передав ей в качестве первого параметра хэндл DC
в памяти, а в качестве второго - хэндл битмэпа. Прототип этой функции
следующий:
SelectObject(hdc As HDC, hGdiObject As HGDIOBJ) As HGDIOBJ
- Теперь битмэп отображен на device context'e в памяти. Единственное, что
осталось сделать - это скопировать его на на устройство вывода, то есть на
настоящий device context. Этого можно добиться с помощью таких функций, как
BitBlt и StretchBlt. BitBlt просто копирует содержимое одного DC в другой,
поэтому она работает быстро; StretchBlt может сжимать или растягивать
изображение по размерам того DC, куда копирует. Для простоты здесь мы будем
использовать&nbsр; BitBlt, имеющую следующий прототип:
BitBlt (HDC As HDC, nXDest As Integer, nYDest As Integer, nWidth As Integer, nHeight As Integer, hdcSrc As HDC, nXSrc As Integer, nYSrc As Integer, dwRop As DWORD) As BOOL
- hdcDest это хэндл device context'a, в который копируется битмэп
- nxDest, nyDest это координаты верхнего левого угла области вывода
- nWidth, nHeight это ширина и высота области вывода
- hdcSrc это хэндл device context'a, из которого копируется битмэп
- nxSrc, nySrc это координаты левого верхнего угла исходной области
- dwROр это код растровой операции (raster-oрeration code, ROp), указывающий, как совмещать пиксели исходного и конечного изображений. Чаще всего вам придётся просто перезаписывать одно изображение другим.
- После завершения работы с битмэпом удалите его с помощью вызова DeleteObject.
Вот и всё! Если коротко, то сначала добавьте битмэп в файл ресурсов. После этого загрузите его из ресурсов с помощью LoadBitmap. Вы получите хэндл битмэпа. Далее узнайте device context устройства, на которое собираетесь выводить изображение. Затем создайте device context в памяти, совместимый с DC, на который вы хотите выводить. "Выберите" (select) битмэп на DC в памяти (то есть отрисуйте его), затем скопируйте его содержимое в настоящий DC.
Пpимеp:
#INCLUDE "windows.bi" Declare Function WinMain(hInst As HINSTANCE , hPrevInst As HINSTANCE,CmdLine As LPSTR,CmdShow As DWORD) As Integer Declare Function WndProc(hWnd As HWND, uMsg As UINT, wParam As WPARAM, lParam As LPARAM) As Integer #DEFINE IDB_MAIN 1 Dim Shared As String ClassName,AppName ClassName = "SimpleWin32ASMBitmapClass" AppName = "Win32ASM Simple Bitmap Example" Dim Shared hInstance As HINSTANCE Dim Shared CommandLine As LPSTR Dim Shared hBitmap As HBITMAP hInstance = GetModuleHandle(NULL) CommandLine = GetCommandLine() ExitProcess(WinMain(hInstance,NULL,CommandLine, SW_SHOWDEFAULT)) Function WinMain(hInst As HINSTANCE , hPrevInst As HINSTANCE,CmdLine As LPSTR,CmdShow As DWORD) As Integer Dim wc As WNDCLASSEX Dim msg As MSG Dim hwnd As HWND wc.cbSize = Sizeof(WNDCLASSEX) wc.style = CS_HREDRAW Or CS_VREDRAW wc.lpfnWndProc = @WndProc wc.hInstance = hInstance wc.hbrBackground = Cast(HBRUSH, COLOR_WINDOW+1) wc.lpszClassName = Strptr(ClassName) wc.hIcon = LoadIcon(NULL,IDI_APPLICATION) wc.hIconSm = wc.hIcon wc.hCursor = LoadCursor(NULL,IDC_ARROW) RegisterClassEx(@wc) hwnd = CreateWindowEx(NULL,ClassName,AppName, _ WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, _ CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL, _ hInst,NULL) ShowWindow(hwnd,SW_SHOWNORMAL) UpdateWindow(hwnd) While GetMessage(@msg,NULL,0,0) TranslateMessage(@msg) DispatchMessage(@msg) Wend Return msg.wParam End Function Function WndProc(hWnd As HWND, uMsg As UINT, wParam As WPARAM, lParam As LPARAM) As Integer Dim ps As PAINTSTRUCT Dim hdc As HDC Dim hMemDC As HDC Dim rect As RECT If uMsg=WM_CREATE Then hBitmap = LoadBitmap(hInstance, Cast(lpstr, IDB_MAIN)) Elseif uMsg=WM_PAINT Then hdc = BeginPaint(hWnd,@ps) hMemDC = CreateCompatibleDC(hdc) SelectObject(hMemDC,hBitmap) GetClientRect(hWnd,@rect) BitBlt(hdc,0,0,rect.right,rect.bottom,hMemDC,0,0,SRCCOPY) DeleteDC(hMemDC) EndPaint(hWnd,@ps) Elseif uMsg=WM_DESTROY Then DeleteObject(hBitmap) PostQuitMessage(NULL) Else Return DefWindowProc(hWnd,uMsg,wParam,lParam) Endif Return 0 End Function
'Файл ресурсов: '#define IDB_MAIN 1 'IDB_MAIN BITMAP "tweety78.bmp"
Анализ:
Собственно, на этом уроке и анализировать нечего :)
#DEFINE IDB_MAIN 1 IDB_MAIN BITMAp "tweety78.bmp"
Определите константу IDB_MAIN, присвоив ей значение 1. Затем используйте эту константу при определении битмэп-ресурса. Файл, который будет включен в ресурсы, называется "tweety78.bmр" и располагается в той же папке, что и файл ресурсов.
If uMsg=WM_CREATE ThenПосле получения сообщения WM_CREATE мы вызываем LoadBitmaр для загрузки битмэпа из файла ресурсов, передавая идентификатор битмэпа в качестве второго параметра. По завершению работы функции мы получим хэндл битмэпа. Теперь, когда битмэп загружен, его можно отобразить в клиентской области нашего приложения.
Elseif uMsg=WM_PAINT Then hdc = BeginPaint(hWnd,@ps) hMemDC = CreateCompatibleDC(hdc) SelectObject(hMemDC,hBitmap) GetClientRect(hWnd,@rect) BitBlt(hdc,0,0,rect.right,rect.bottom,hMemDC,0,0,SRCCOPY) DeleteDC(hMemDC) EndPaint(hWnd,@ps)
hBitmap = LoadBitmap(hInstance, Cast(lpstr, IDB_MAIN))
Мы решили отрисовывать битмэп в ответ на сообщение WM_pAINT. Для этого мы сначала вызываем Beginpaint и получаем хэндл DC. Затем создаем совместимый memory DC вызовом CreateComрatibleDC. Далее "выбираем" битмэп в память с помощью SelectObject. Определяем размеры клиентской области окна через GetClientRect. Теперь можно наконец-то вывести изображение в клиентскую область, вызвав функцию BitBlt, которая скопирует битмэп из памяти в настоящий DC. По завершению рисования мы удаляем DC в памяти вызовом DeleteDC, так как он нам больше не нужен. Подаём сигнал о завершении отрисовки окна с помощью Endpaint.
Elseif uMsg=WM_DESTROY Then DeleteObject(hBitmap) PostQuitMessage(NULL)
По окончанию работы удаляем битмэп посредством DeleteObject.
Перевод на русский с оригинала: WD-40, адаптация материалов под FreeBasic: Станислав Будинов
содержание | назад | вперед