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

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

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

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

Win32 API. Урок 7. Мышь

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

Теория:

Так же, как и при вводе с клавиатуры, Windows определяет и посылает уведомления об активности мыши относительно какого-либо окна. Эта активность включает в себя нажатия на правую и левую клавишу, передвижения курсора через окно, двойные нажатия. В отличие от клавиатуры, сообщения от которой направляются окну, имеющему в данный момент фокус ввода, сведения о котором передаются окну, над которым находится мышь, независимо от того, активно оно или нет. Вдобавок, есть сообщения от мыши, связанные с не-клиентской части окна, но, к счастью, мы можем их, как правило, игнорировать. Мы можем сфокусироваться на связанных с клиентской областью.

Есть два сообщения для каждой из кнопок мыши: WM_LBUTTONDOWN, WM_RBUTTONDOWN и WM_LBUTTONUP, WM_RBUTTONUP. Если мышь трехкнопочная, то есть еще WM_MBUTTONDOWN и WM_MBUTTONUP. Когда курсор мыши двигается над клиентской областью, Windows шлет WM_MOUSEMOVE окну, над которым он находится. Окно может получать сообщения о двойных нажатиях, WM_LBUTTONDBCLK или WM_RBUTTONDBCLK, тогда и только тогда, когда окно имеет стиль CS_DBLCLKS, или же оно будет получать только серию сообщений об одинарных нажатиях.

Во всех этих сообщениях значение lParam содержит позицию мыши. Нижнее слово - это x-координата, верхнее слово - y-координата верхнего левого угла клиентской области окна. wParam содержит информацию о состоянии кнопок мыши, Shift'а и Ctrl'а.

Пример:

Код:

' мышь
#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" ' название программы
dim shared MouseClick as uByte ' флаг клика мыши
dim shared hitpoint  as POINT ' координаты x и y
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

function = 0
select case uMsg  'начинаем обработку сообщений
case WM_DESTROY ' если пользователь закрывает окно
PostQuitMessage(0) ' выходим из программы
exit function
case WM_LBUTTONDOWN ' если нажали левую кнопку мыши
hitpoint.x = loword(lParam) ' сохраним координату x мыши
hitpoint.y = hiword(lParam) ' сохраним координату y мыши
MouseClick = TRUE ' установим флаг состояния
InvalidateRect(hWnd,NULL,TRUE) ' вынудить Windows послать сообщение WM_PAINT
case WM_PAINT ' сообщение отрисовки окна

'получим контекст устройства в hdc и начнем отрисовку
hdc = BeginPaint(hWnd, @ps)
if MouseClick = TRUE then ' если флаг клика мыши установлен в TRUE
    TextOut(hdc,hitpoint.x,hitpoint.y,AppName,lstrlen(@AppName)) ' отрисовать символ
end if
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

Анализ:

case WM_LBUTTONDOWN
hitpoint.x = loword(lParam)
hitpoint.y = hiword(lParam)
MouseClick = TRUE
InvalidateRect(hWnd,NULL,TRUE)

Процедура окна ждет нажатия на левую клавишу мыши. Когда она получает WM_LBUTTONDOWN, lParam содержит координаты курсора мыши в клиентской области. Процедура сохраняет их в переменной типа POINT, определенной следующим образом:

type POINT
x as LONG
y as LONG
end type

После сохранения позиции мыши, мы устанавливаем флаг, MouseClick, в TRUE для того, чтобы отрисовывающий код в секции WM_PAINT, знал, что было нажатие в клиентской области, и значит поэтому он может нарисовать строку в позиции, где была мышь при нажатии. Затем мы вызываем функцию InvalidateRect, чтобы заставить окно полностью перерисовать ее клиентскую область.

if MouseClick = TRUE then
   TextOut(hdc,hitpoint.x,hitpoint.y,@AppName,lstrlen(@AppName)) ' отрисовать символ
end if

Отрисовывающий код в секции WM_PAINT должен проверять, установлен ли флаг MouseClick в TRUE, потому что когда окно создается, процедура окна получает сообщение WM_PAINT в то время, когда не было сделано еще ни одного нажатия, то есть строку отрисовывать нельзя. Мы инициализируем MouseClick в FALSE и меняем ее значение в TRUE, когда происходит нажатие на мышь. Если по крайней мере одно нажатие на мышь произошло, она вырисовывает строку в клиентской области в позиции, где была мышь при нажатии. Заметьте, что она вызывает lstrlen для того, чтобы определить длину строки и шлет полученное значение в качестве последнего параметра функции TextOut.

[C] Iczelion, пер. Aquila.

electrik

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

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

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

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


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