платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 4 - Отрисовка текста

Предыдущая тема Следующая тема Перейти вниз

платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 4 - Отрисовка текста

Сообщение  electrik в Вс Июн 28, 2009 7:44 pm

Win32 API. Урок 4. Отрисовка текста

В этом разделе мы научимся как "рисовать" текст в клиентской части окна. Мы также узнаем о контекстах устройств.

Теория:

Текст в Windows - это вид GUI объекта. Каждый символ создан из множества пикселей (точек), которые соединены в различные рисунки. Вот почему мы "рисуем" их, а не "пишем". Обычно вы рисуете текст в вашей клиентской области (на самом деле, вы можете рисовать за пределами клиентской области, но это другая история). Помещения текста на экран в Windows разительно отличается от того, как это делается в DOS'е. В DOS'е размерность экрана 80x25. Но в Windows, экран используется одновременно несколькими программами. Необходимо следовать определенным правилам, чтобы избежать того, чтобы программы рисовали поверх чужой части экрана. Windows обеспечивает это, ограничивая область рисования его клиентской частью. размер клиентской части окна совсем не константа. Пользователь может изменить его в любой момент, поэтому вы должны определять размеры вашей клиентской области динамически. Перед тем, как вы нарисуете что-нибудь на клиентской части, вы должны спросить разрешения у операционной системы. Действительно, теперь у вас нет абсолютного контроля над экраном, как это было в DOS'е. Вы должны спрашивать Windows, чтобы он позволил вам рисовать в вашей собственной клиентской области. Windows определит размер вашей клиентской области, фонт, цвета и другие графические атрибуты и пошлет хэндл контекста устройства (device context) программе. Тогда вы сможете использовать его как пропуск к рисованию.

Что такое контекст устройства? Это всего структура данных, использующаяся Windows внутренне. Контекст устройства сопоставлен определенному устройству, такому как принтер или видео-адаптер. Для видеодисплея, контекст устройства обычно сопоставлен определенному окну на экране.

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

Они существуют, чтобы помочь снизить загрузку из-за необходимости указывать эти атрибуты при каждом вызове функций GDI.

Когда программе нужно отрисовать что-нибудь, она должна получить хэндл контекста устройства. Как правило, есть несколько путей достигнуть этого.

• Вызовите BeginPaint в ответ на сообщение WM_PAINT.
• Вызовите GetDC в ответ на другие сообщения.
• Вызовите CreateDC, чтобы создать ваш собственный контекст устройства.

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

Нельзя делать так: получить хэндл, обрабатывая одно сообщение, и освободить его, обрабатывая другое.

Windows посылает сообщение WM_PAINT окну, чтобы уведомить его о том, что настало время для перерисовки клиентской области. Windows не сохраняет содержимое клиентской части окна. Взамен, когда происходит ситуация, служащая основанием для перерисовки окна, Windows помещает в очередь сообщений окна WM_PAINT.
Окно должно само перерисовать свою клиентскую область. Вы должны поместить всю информацию о том, как перерисовывать клиентскую область в секции WM_PAINT вашей процедуры окна, так чтобы она могла отрисовать всю клиентскую часть, когда будет получено сообщение WM_PAINT. Также вы должны представлять себе, что такое invalid rectangle. Windows определяет i.r. как наименьшую прямоугольную часть окна, которая должна быть перерисована. Когда Windows обнаруживает i.r. в клиентской области окна, оно посылает сообщение WM_PAINT этому окну. В ответ на сообщение, окно может получить структуру PAINTSTRUCT, которая среди прочего содержит координаты i.r.. Вы вызываете функцию Beginpaint в ответ на сообщение WM_PAINT, чтобы сделать неполноценный прямоугольник снова нормальным.
Если вы не обрабатываете сообщение WM_PAINT, то по крайней мере вам следует вызвать DefWindowProc или ValidateRect, иначе Windows будет слать вам WM_PAINT постоянно.

Ниже показаны шаги, которые вы должны выполнить, обрабатывая сообщение WM_PAINT:

• Получить хэндл контекста устройства с помощью BeginPaint.
• Отрисовать клиентскую область.
• Освободить хэндл функцией EndPaint.

Заметьте, что вы не обязаны думать о том, чтобы пометить неполноценные прямоугольники как нормальные, так как это делается автоматически при вызове Beginpaint.
Между связкой Beginpaint-Endpaint, вы можете вызвать любую другую графическую функцию, чтобы рисовать в вашей клиентской области. Практически все из них требуют хэндл контекста устройства.

Содержимое:

Мы напишем программу, отображающую текстовую строку "Win32 FreeBasic is great and easy!" в центре клиентской области.

Код:

' отрисовка текста
#include "windows.bi"

declare function WinMain ( byval hInst as HINSTANCE, _
byval hPrevInst as HINSTANCE, _
  byval szCmdLine as LPSTR, _
  byval iCmdShow as integer ) as integer

' начало программы
#define ClassName "SimpleWinClass" ' имя класса окна
#define AppName "Our First Window" ' имя программы
end WinMain( GetModuleHandle( NULL ) ,NULL,GetCommandLine() , SW_SHOWNORMAL ) ' вызвать основную функцию
' здесь заканчивается программа

' процедура окна
function  WndProc _
(byval hwnd as HWND, _ ' хэндл окна
byval uMsg as UINT, _ ' сообщение
byval wParam as WPARAM, _ ' дополнительный  параметр сообщений
byval lParam as LPARAM) as LRESULT ' дополнительный параметр сообщений

dim hDc as HDC ' хэндл контекста устройства
dim ps as PAINTSTRUCT ' структура PAINTSTRUCT
dim rect as RECT ' размеры клиентской области
function = 0
select case uMsg  'начинаем обработку сообщений
case WM_DESTROY ' если пользователь закрывает окно
PostQuitMessage(0) ' выходим из программы
exit function
case WM_PAINT ' сообщение отрисовки окна
'получим контекст устройства в hdc и начнем отрисовку
hdc = BeginPaint(hWnd, @ps)
GetClientRect(hWnd, @rect) ' получаем размеры клиентской области
DrawText _ ' выведем текст
( hdc, _ ' хэндл контекста устройства
"Win32 FreeBasic is great and easy!", _ ' выводимый текст
-1, _
@rect, _ ' указатель на прямоугольник(структура rect)
DT_SINGLELINE or DT_CENTER or DT_VCENTER) ' значение, определяющее вывод текста в прямоугольнике
EndPaint(hWnd, @ps) ' завершаем отрисовку и освобождаем хэндл контекста устройства
end select
function = DefWindowProc(hWnd,uMsg,wParam,lParam) ' Дефаултная функция обработки окна
end function


'функция WinMain
function WinMain _
(byval hInst as HINSTANCE, _ ' хэндл программы
byval hPrevInst as HINSTANCE, _ 'в win32 всегда 0
byval szCmdLine as LPSTR, _  'указатель на командную строку
byval iCmdShow as integer ) as integer  ' состояние окна при первом появлении

dim wc as WNDCLASSEX ' структура параметров окна
dim wMsg as MSG  ' структура сообщений
dim hWnd as HWND ' хэндл окна

 'структура класса окна wc
with wc ' заполняем структуру wc
.cbSize = SIZEOF( WNDCLASSEX )  ' размер структуры WNDCLASSEX
.style = CS_HREDRAW or CS_VREDRAW  ' Стиль окна
.lpfnWndProc = @WndProc ' Адрес процедуры окна WndProc
.cbClsExtra = NULL  ' резервирование  дополнительных байт за концом структуры
.cbWndExtra = NULL
.hInstance = hInst  ' хэндл модуля
.hbrBackground = cast(HGDIOBJ, COLOR_WINDOW+1) ' Цвет фона
.lpszMenuName = NULL ' Хэндл меню
.lpszClassName = @ClassName ' имя класса окна
.hIcon = LoadIcon( NULL,IDI_APPLICATION ) ' Хэндл иконки
.hIconSm = .hIcon 'Хэндл маленькой иконки
.hCursor = LoadCursor( NULL,IDC_ARROW) ' Хэндл курсора
end with

' регистрация нашего класса окна
if(RegisterClassEx(@wc) = FALSE) then
MessageBox(0,"Не могу зарегистрировать класс окна","Ошибка",0)
end 1
end if

' Создадим окно
hwnd = CreateWindowEx _
(NULL, _ ' дополнительные стили
ClassName, _ ' строка с именем класса окна
AppName, _ ' строка с именем окна
WS_OVERLAPPEDWINDOW, _ ' стиль окна
CW_USEDEFAULT, _ ' X
CW_USEDEFAULT, _ ' Y
CW_USEDEFAULT, _ ' ширина окна
CW_USEDEFAULT, _ ' высота окна
NULL, _ ' хэндл родительского окна
NULL, _ ' хэндл меню
hInst, _ ' хэндл модуля
NULL) ' указатель на структуру данных

ShowWindow( hwnd,iCmdShow) ' отобразить наше окно на десктопе
UpdateWindow( hwnd) ' обновить клиентскую область

while( GetMessage( @wMsg, NULL, 0, 0 ) <> FALSE )  'цикл сообщений
TranslateMessage( @wMsg )
DispatchMessage( @wMsg )
wend
function = wMsg.wParam
end function

Анализ:

Большая часть этого кода точно такая же, как и пример из Урока 3. Я объясню только важные изменения.

dim hDc as HDC ' хэндл контекста устройства
dim ps as PAINTSTRUCT ' структура PAINTSTRUCT
dim rect as RECT

Это несколько переменных, использующихся в нашей секции WM_PAINT. Переменная hdc используется для сохранения хэндла контекста устройства, возвращенного функцией BeginPaint. ps - это структура PAINTSTRUCT. Обычно вам не нужны значения этой структуры. Она передается функции BeginPaint и Windows заполняет ее подходящими значениями. Затем вы передаете ps функции EndPaint, когда заканчиваете отрисовку клиентской области. rect - это структура RECT, определенная
следующим образом:

type RECT
left as LONG
top as LONG
right as LONG
bottom as LONG
end type

Left и top - это координаты верхнего левого угла прямоугольника. Right и bottom - это координаты нижнего правого угла. Помните одну вещь: начала координатных осей находятся в левом верхнем углу клиентской области, поэтому точка y=10 НИЖЕ, чем точка y=0.

case WM_PAINT
hdc = BeginPaint(hWnd, @ps)
GetClientRect(hWnd, @rect)
DrawText _
( hdc, _
"Win32 assembly is great and easy!", _
-1, _
@rect, _
DT_SINGLELINE or DT_CENTER or DT_VCENTER)
EndPaint(hWnd, @ps)

В ответ на сообщение WM_PAINT, вы вызываете BeginPaint, передавая ей хэндл окна, в котором вы хотите рисовать структуру типа PAINTSTRUCT в качестве параметров. После успешного вызова, функция возвращает хэндл контекста устройства. После вы вызываете GetClientRect, чтобы получить размеры клиентской
области. размеры возвращаются в переменной rect, которую вы передаете функции DrawText как один из параметров. Синтаксис DrawText'а таков:

function DrawText _
(byval hDc as HDC, _
byval lpString as LPCSTR, _
byval nCount as integer, _
byval lpRect as LPRECT, _
byval uFormat as UINT) as integer

DrawText = это высокоуровневая Api функция вывода текста. Она берет на себя такие вещи как перенос слов, центровка и т.п., так что вы можете сконцентрироваться на строке, которую вы хотите нарисовать. Ее низкоуровневый брат, TextOut, будет описан в следующем Уроке. DrawText подгоняет строку под прямоугольник.
Она использует выбранный в настоящее время фонт, цвет и фон для отрисовки текста. Слова переносятся так, чтобы строка влезла в границы прямоугольника.
DrawText возвращает высоту выводимого текста в единицах устройства, в нашем случае в пикселях. Давайте посмотрим на ее параметры:

• hdc - хэндл контекста устройства
• lpString - указатель на строку, которую вы хотите нарисовать в прямоугольнике. Строка должна заканчиваться NULL'ом, или же вам придется указывать ее длину
в следующем параметре, nCount.
• nCount - количество символов для вывода. Если строка заканчивается NULL'ом, nCount должен быть равен -1. В противоположном случае, nCount должен содержать
количество символов в строке.
• lpRect - указатель на прямоугольник (структура типа RECT), в котором вы хотите рисовать строку. Заметьте, что прямоугольник ограничен, то есть вы не можете нарисовать строку за его пределами.
• uFormat - значение, определяющее как строка отображается в прямоугольнике. Мы используем три значения, скомбинированные оператором "or":

• DT_SINGLELINE указывает, что текст будет располагаться в одну линию
• DT_CENTER центрирует текст по горизонтали
• DT_VCENTER центрирует тест по вертикали. Должен использоваться вместе с DT_SINGLELINE.

После того, как вы отрисовали клиентскую область, вы должны вызвать функцию EndPaint, чтобы освободить хэндл контекста устройства .

Вот и все. Мы можем указать главные идеи:

• Вы вызываете связку BeginPaint-EndPaint в ответ на сообщение WM_PAINT. Делайте все, что вам нужно с клиентской областью между вызовами этих двух функций.
• Если вы хотите перерисовать вашу клиентскую область в ответе на другие сообщения, у вас есть два выбора:

• Используйте связку GetDC-ReleaseDC и делайте отрисовку между вызовами этих функций.
• Вызовите Invalidaterect или UpdateWindow, чтобы Windows послала сообщение WM_PAINT вашему окну.

[C] Iczelion, пер. Aquila.

electrik

Сообщения : 391
Дата регистрации : 2008-09-02
Возраст : 36
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург

Посмотреть профиль

Вернуться к началу Перейти вниз

Предыдущая тема Следующая тема Вернуться к началу


 
Права доступа к этому форуму:
Вы не можете отвечать на сообщения