Assembler - Просто и Эффективно. Глава #9 - Контролы
Assembler
Глава #9 - Контролы
Контролы (Controls)
Большая часть свойств окна завсит от класса (процедуры обработки сообщений). Для упрощения программирования, в Windows существуют классы, выполняющие наиболее распространенные задачи.
Используются для отображение элементов управления: кнопки, поля ввода, списки и т.д.
-------------------------------
Общая информация.
Для использования большинства контролов, нужно создать дочернее окно, указав класс контрола в качестве класса окна.
Младшое слово стиля окна позволяет задать некоторые свойства, специфичные для каждого контрола. Старшое слово (константы ws_) - стандартные свойства, общие для всех окон.
Контролы управляются посылкой им сообщений. Обычно для посылки сообщений используется функция SendMessageA или SendDlgItemMessageA.
При происхождении некоторых событий, контролы посылают окну-родителю сообщения (Notifications): WM_COMMAND, WM_NOTIFY и д.р.
Для того, чтобы пользователь мог осуществлять навигацию при помощи клавиши TAB, контрол должен иметь стиль WS_TABSTOP, и в цикл обработки сообщений должна быть дабавлена ф-ция IsDialogMessage (с.м. пример).
В MSDN: User Interface Design and Development->Windows Controls находится подробная информация об использовании контролов, их стилях, используемых сообщениях и т.д
-------------------------------
Размеры/Координаты
Существует два понятия о размере окна:
Screen Rect- Общий прямоугольник окна, включая рамку, заголовок окна, полосы прокрутки и т.д. Указывается при создании окна.
Client Rect - Прямоугольник, означающий полезную площадь окна.
Для одного и тогоже Client Rect'а при разных настройках Windows нужно указывать разный Screen Rect. Для вычисления необходимого Screen Rect'а на основе Client Rect'а можно использовать функцию AdjustWindowRect.
Также, в настройках системы пользователя может быть указан любой размер шрифта, из- за чего текст в контролах может не соответствовать размеру контрола. Можно решить эту проблему, либо меняя размер контролов в зависимости от размера шрифта, либо ипользвать шрифт фиксированного размера.
Для создания нужного шрифта можно использовать ф-цию CreateFontIndirectA
-------------------------------
Пример
Для компиляции примера необходим MASM. Об использовании этого компилятора с.м. главу #8 (asm32.nm.ru - кнопка архив)
.386
.model flat,stdcall
;используем inc и lib файлы из пакета masm32 (с.м главу #8)
include c:\masm32\include\windows.inc
include c:\masm32\include\kernel32.inc
includelib c:\masm32\lib\kernel32.lib
include c:\masm32\include\user32.inc
includelib c:\masm32\lib\user32.lib
include c:\masm32\include\gdi32.inc
includelib c:\masm32\lib\gdi32.lib
;Для более удобной модификации / настройки программы,
;используемые числа объявляем константами.
EditSizeX equ 200 ;длинна Edit контрола
ControlsY equ 20 ;высота контролов
WndSpace equ 5 ;расстояние между контролами
BtnSizeX equ 85 ;длинна кнопки
WndSizeX equ WndSpace*3+EditSizeX+BtnSizeX ;длинна окна
WndSizeY equ WndSpace*2+ControlsY ;высота окна
ButtonID equ 100 ;ID кнопки
EditID equ 200 ;ID Edit контрола
.data
ProgramClassName db 'AnyClassName',0 ;класс основонго окошка
ButtonClassName db 'Button',0 ;класс контрола - кнопки
EditClassName db 'Edit',0 ;класс контрола - поля ввода
WindowText db 'Заголовок окна',0
MsgTitle db 'Текст контрола Edit:',0
ButtonText db 'Display Text',0
WndRect RECT<0,0,WndSizeX,WndSizeY> ;Client Rect окна
WClass WNDCLASSEX <>
MsgS MSG <>
hMainWindow dd ? ;хэндл главного окна
hButton dd ? ;хэндл кнопки
hEdit dd ? ;хэндл поля ввода
hEditFont dd ? ;хэндл шрифта поля ввода
hBtnFont dd ? ;хэндл шрифта кнопки
NCM NONCLIENTMETRICS<>
TextBuffer db 300 dup (?)
TBS =$-offset TextBuffer
.code
start:
;получим информацию о системе. нас интересуют используемые шрифты.
mov NCM.cbSize,sizeof NONCLIENTMETRICS
invoke SystemParametersInfo,SPI_GETNONCLIENTMETRICS,\
sizeof NONCLIENTMETRICS, offset NCM,0
;создадим шрифт, высотой ControlsY-2
mov NCM.lfMessageFont.lfHeight,ControlsY-2
invoke CreateFontIndirect,offset NCM.lfMessageFont
mov [hEditFont],eax
;создадим шрифт, высотой ControlsY-4
mov NCM.lfMessageFont.lfHeight,ControlsY-4
invoke CreateFontIndirect,offset NCM.lfMessageFont
mov [hBtnFont],eax
;зарегистрируем класс главного окна (см главу #7)
mov WClass.cbSize,size WNDCLASSEX
mov WClass.style,CS_HREDRAW or CS_VREDRAW
mov WClass.lpfnWndProc,offset MainWindowProc
mov WClass.cbClsExtra,0
mov WClass.cbWndExtra,0
invoke GetModuleHandle,0
mov WClass.hInstance,eax
invoke LoadIcon,0,IDI_APPLICATION
mov WClass.hIcon,eax
mov WClass.hIconSm,eax
invoke LoadCursor,0,IDC_ARROW
mov WClass.hCursor,eax
mov WClass.hbrBackground,COLOR_WINDOW
mov WClass.lpszMenuName,0
mov WClass.lpszClassName,offset ProgramClassName
invoke RegisterClassEx,offset WClass
;определим размер основного окна, на основе необходимого Client Rect'а
MainWindowstyle="WS_CAPTION" or WS_DLGFRAME or WS_VISIBLE or WS_MINIMIZEBOX or WS_SYSMENU
invoke AdjustWindowRect,offset WndRect,MainWindowStyle,0
mov eax,WndRect.right
sub eax,WndRect.left
mov ecx,WndRect.bottom
sub ecx,WndRect.top
;создадим главное окно
invoke CreateWindowEx,0,offset ProgramClassName,offset WindowText,\
MainWindowStyle,CW_USEDEFAULT,CW_USEDEFAULT,eax,ecx,\
0,0,[WClass.hInstance],0
mov [hMainWindow],eax
;создадим Edit контрол в главном окне
invoke CreateWindowEx,WS_EX_STATICEDGE,offset EditClassName,0,\
WS_TABSTOP or WS_CHILD or WS_VISIBLE or ES_AUTOHSCROLL,\
WndSpace,WndSpace,EditSizeX,ControlsY,\
[hMainWindow],EditID,[WClass.hInstance],0
mov [hEdit],eax
;установим шрифт Edit контрола
invoke SendMessage,[hEdit],WM_SETFONT,[hEditFont],1
invoke SetFocus,[hEdit] ;сделаем его активным
;создадим кнопку в главном окне
invoke CreateWindowEx,0,offset ButtonClassName,offset ButtonText,\
WS_TABSTOP or WS_DISABLED or WS_CHILD or WS_VISIBLE,\
WndSpace*2+EditSizeX,WndSpace,BtnSizeX,ControlsY,\
[hMainWindow],ButtonID,[WClass.hInstance],0
mov [hButton],eax
invoke SendMessage,eax,WM_SETFONT,[hBtnFont],1 ;установим шрифт кнопки
MsgLoop:
invoke GetMessage,offset MsgS,0,0,0
inc eax
jz EndMsgLoop
dec eax
jz EndMsgLoop
invoke IsDialogMessage,[hMainWindow],offset MsgS
or eax,eax
jnz MsgLoop
invoke TranslateMessage,offset MsgS
invoke DispatchMessage,offset MsgS
jmp MsgLoop
EndMsgLoop:
invoke ExitProcess,0
MainWindowProc proc hwnd:dword,uMsg:dword,wParam:dword,lParam:dword
cmp [uMsg],WM_COMMAND
jnz NotCommand
;обработка WM_COMMAND
cmp word ptr [wParam+2],BN_CLICKED
jnz NotBtnClick
cmp word ptr [wParam],ButtonID
jnz CallDefProc
;кнопка ButtonID нажата.
;получим текст Edit контрола hEdit в память TextBuffer размером TBS
invoke GetWindowText,[hEdit],offset TextBuffer,TBS
;покажем сообщение, текст которого в TextBuffer
invoke MessageBox,[hwnd],offset TextBuffer,offset MsgTitle,MB_ICONINFORMATION
invoke SetFocus,[hEdit]
jmp CallDefProc
NotBtnClick:
cmp word ptr [wParam+2],EN_UPDATE
jnz CallDefProc
cmp word ptr [wParam],EditID
jnz CallDefProc
;произошли изменения текста в контроле EditID. Получим длинну его текста.
invoke GetWindowTextLength,[lParam]
xor ecx,ecx
or eax,eax
setnz cl
invoke EnableWindow,[hButton],ecx ;установим состояние кнопки
NotCommand:
;стандартная часть процедуры обработки сообщений с.м главу #7.
cmp [uMsg],WM_DESTROY
jnz NotWmDestroy
invoke PostQuitMessage,0
xor eax,eax
ret
NotWmDestroy:
CallDefProc:
invoke DefWindowProc,[hwnd],[uMsg],[wParam],[lParam]
ret
MainWindowProc endp
end start
Чтобы увидеть, как программа меняет размер шрифта в зависимости от размера контролов, измените значение константы ControlsY.
-------------------------------
Ресурсы.
Создавать окна и контролы при помощи ф-ции CreateWindowExA удобно для окон:
конфигурация которых заранее неопределена (типа MessageBox)
содержащих небольшое количество контролов (пример: программа Блокнот).
Для создания окон с большим количеством контролов, имеющих постоянный размер (например, Калькулятор в Windows), удобнее использовать ресурсы.
Также ресурсы могут содержать иконки, курсоры, меню, изображения, и т.д
Об использовании ресурсов будет рассказанно в следующей главе.
-------------------------------
Содержание дальнейших выпусков зависит от вас. Будут разъясняться те темы, которые непонятны большинству читателей. Присылайте свои вопросы и предложения по адресу: asm32@nm.ru . -------------------------------
Автор рассылки Владимир Пронин. Любое коммерческое использование материалов рассылки без ведома и прямого согласия автора запрещено.
Письма присланные автору рассылки могут быть опубликованы целиком или частично без предварительного уведомления. Если вы не хотите, чтобы ваше письмо было опубликовано укажите это в начале письма.
Перепечатка материалов разрешена только с непосредственной ссылкой на asm32.nm.ru