КАК работает мышка в Win32 API?

С вашего позволения, начну этот раздел сразу же с примера. Наше окно будет реагировать на банальный щелчок по нему левой кнопкой. В ответ на это в том месте, где был сделан щелчок, будет появляться фраза: "Поздравляю, теперь вы умеет работать с мышью!". Так мы сразу убьём двух зайцев - научимся реагировать на мышь и узнавать в каком месте было сделано нажатие.

#include "windows.h"

//Создаём прототип функции окна
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

char szIconName[]="MYICON"; //имя иконки
char szProgName[]="Progname"; //имя программы
char szText[]="Поздравляю, теперь вы умеете работать с мышью!";

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{

HWND hWnd; //идентификатор окна
MSG lpMsg; //идентификатор сообщения
WNDCLASS w; //создаём экземпляр структуры WNDCLASS

//И начинаем её заполнять
w.lpszClassName=szProgName; //имя программы - объявлено выше
w.hInstance=hInstance; //идентификатор текущего приложения
w.lpfnWndProc=WndProc; //указатель на функцию окна
w.hCursor=LoadCursor(NULL, IDC_ARROW); //загружаем курсор
w.hIcon=LoadIcon(hInstance, szIconName); //загружаем нашу иконку
w.lpszMenuName=0; //меню пока не будет
w.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); //цвет фона окна
w.style=CS_HREDRAW|CS_VREDRAW; //стиль - перерисовываемое по х и по у
w.cbClsExtra=0;
w.cbWndExtra=0;

//Если не удалось зарегистрировать класс окна - выходим
if(!RegisterClass(&w))
return 0;

//Создадим окно в памяти, заполнив аргументы CreateWindow
hWnd=CreateWindow(szProgName, //Имя программы
"Моя первая программа!", //Заголовок окна
WS_OVERLAPPEDWINDOW, //Стиль окна - перекрывающееся
100, //положение окна на экране по х
100, //по у
500, //размеры по х
400, //по у
(HWND)NULL, //идентификатор родительского окна
(HMENU)NULL, //идентификатор меню
(HINSTANCE)hInstance, //идентификатор экземпляра программы
(HINSTANCE)NULL); //отсутствие дополнительных параметров

//Выводим окно из памяти на экран
ShowWindow(hWnd, nCmdShow);
//Обновим содержимое окна
UpdateWindow(hWnd);

//Цикл обработки сообщений

while(GetMessage(&lpMsg, NULL, 0, 0)) { //Получаем сообщение из очереди
TranslateMessage(&lpMsg); //Преобразует сообщения клавиш в символы
DispatchMessage(&lpMsg); //Передаёт сообщение соответствующей функции окна
}
return(lpMsg.wParam);
}

//Функция окна
LRESULT CALLBACK WndProc(HWND hWnd, UINT messg,
WPARAM wParam, LPARAM lParam)
{
HDC hdc; //создаём контекст устройства
PAINTSTRUCT ps; //создаём экземпляр структуры графического вывода

//Цикл обработки сообщений
switch(messg)
{

int x,y; //координаты

//Если был щелчок левой или правой кнопкой
case WM_RBUTTONDOWN:
case WM_LBUTTONDOWN:
char *str;
HDC hDC;

hDC=GetDC(hWnd);
x=LOWORD(lParam); //узнаём координаты
y=HIWORD(lParam);

TextOut(hDC, x, y, szText, strlen(szText));

break;

//сообщение выхода - разрушение окна
case WM_DESTROY:
PostQuitMessage(0); //Посылаем сообщение выхода с кодом 0 - нормальное завершение
break;

default:
return(DefWindowProc(hWnd, messg, wParam, lParam)); //освобождаем очередь приложения от нераспознаных
}
return 0;
}

 

Рассмотрим этот фрагмент более детально:

int x,y;

//Если был щелчок левой или правой кнопкой
case WM_RBUTTONDOWN:
case WM_LBUTTONDOWN:
char *str;
HDC hDC;

hDC=GetDC(hWnd);
x=LOWORD(lParam); //узнаём координаты
y=HIWORD(lParam);

TextOut(hDC, x, y, szText, strlen(szText));

break;

Получив сообщения от левой или правой кнопок мыши, окно запишет в переменную lParam значение координат мыши в момент нажатия. lParam для удобства можно рассматривать в виде двух частей - старшей и младшей. Для извлечения значения из каждой части можно применять функции LOWORD() и HIWORD(). В младшем слове будет координата по х, в старшем по у.

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

//Файл SimpleButton.rc
#include "windows.h"

MYICON ICON "serdechko.ico"
MyImage IMAGE "1.bmp"


//Файл SimpleButton.cpp
#include "windows.h"

//Создаём прототип функции окна
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

char szIconName[]="MYICON";
char szImageName[]="MyImage";
char szProgName[]="Progname";

HBITMAP hBitmap;

//объявляем имя программы
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{

HWND hWnd; //идентификатор окна
MSG lpMsg;
hBitmap=LoadBitmap(hInstance, szImageName);

WNDCLASS w; //создаём экземпляр структуры WNDCLASS

//И начинаем её заполнять
w.lpszClassName=szProgName; //имя программы - объявлено выше
w.hInstance=hInstance; //идентификатор текущего приложения
w.lpfnWndProc=WndProc; //указатель на функцию окна
w.hCursor=LoadCursor(NULL, IDC_ARROW); //загружаем курсор
w.hIcon=LoadIcon(hInstance, szIconName);
w.lpszMenuName=0; //меню пока не будет
w.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); //цвет фона окна
w.style=CS_HREDRAW|CS_VREDRAW; //стиль - перерисовываемое по х и по у
w.cbClsExtra=0;
w.cbWndExtra=0;

//Если не удалось зарегистрировать класс окна - выходим
if(!RegisterClass(&w))
return 0;

//Создадим окно в памяти, заполнив аргументы CreateWindow
hWnd=CreateWindow(szProgName, //Имя программы
"Моя первая программа!", //Заголовок окна
WS_OVERLAPPEDWINDOW, //Стиль окна - перекрывающееся
100, //положение окна на экране по х
100, //по у
500, //размеры по х
400, //по у
(HWND)NULL, //идентификатор родительского окна
(HMENU)NULL, //идентификатор меню
(HINSTANCE)hInstance, //идентификатор экземпляра программы
(HINSTANCE)NULL); //отсутствие дополнительных параметров

//Выводим окно из памяти на экран
ShowWindow(hWnd, nCmdShow);
//Обновим содержимое окна
UpdateWindow(hWnd);

//Цикл обработки сообщений

while(GetMessage(&lpMsg, NULL, 0, 0)) { //Получаем сообщение из очереди
TranslateMessage(&lpMsg); //Преобразует сообщения клавиш в символы
DispatchMessage(&lpMsg); //Передаёт сообщение соответствующей функции окна
}
return(lpMsg.wParam);
}

//Функция окна
LRESULT CALLBACK WndProc(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam)
{

//Координаты кнопки
int x1=180;
int y1=250;
int x2=320;
int y2=300;


//Цикл обработки сообщений
switch(messg)
{

int x,y; //координаты мыши
HDC hdc, hmdc;
BITMAP bm;
RECT rect;
PAINTSTRUCT ps;
LOGFONT lf;
HFONT hFont;

case WM_PAINT:
hdc=BeginPaint(hWnd, &ps); //Начинаем рисовать

//Рисуем картинку:
hmdc=CreateCompatibleDC(hdc);
SelectObject(hmdc, hBitmap);
GetObject(hBitmap, sizeof(bm), (LPSTR)&bm);
BitBlt(hdc, 10,10, bm.bmWidth+100, bm.bmHeight, hmdc, 0,0,SRCINVERT);
DeleteDC(hmdc);

HBRUSH hBrush; //Создаём кисть

//Рамка кнопки
hBrush=CreateSolidBrush(RGB(255,255,0));
SelectObject(hdc, hBrush);
RoundRect(hdc,x1,y1,x2,y2,20,20);

//Сама кнопка
hBrush=CreateSolidBrush(RGB(0,255,0));
SelectObject(hdc, hBrush);
RoundRect(hdc,185,255,315,295,20,20);

//Задаём параметры шрифта
lf.lfCharSet=DEFAULT_CHARSET; //значение по умолчанию
lf.lfPitchAndFamily=DEFAULT_PITCH; //значения по умолчанию
strcpy(lf.lfFaceName,"Times New Roman"); //копируем в строку название шрифта
lf.lfHeight=20; //высота
lf.lfWidth=10; //ширина
lf.lfWeight=FW_BOLD; //толщина
lf.lfEscapement=0;//не повёрнутый
lf.lfStrikeOut=0; //на перечёркнутый
lf.lfUnderline=0; //не подчёркнутый

hFont=CreateFontIndirect(&lf); //Cоздали шрифт
SelectObject(hdc, hFont); //Он будет иметь силу только когда мы его выберем

SetTextColor(hdc, RGB(255,0,0)); //зададим цвет текста

SetBkMode(hdc, TRANSPARENT); //текст будет без фона
TextOut(hdc, 218, 263,"Enter", 5); //текст кнопки

EndPaint(hWnd, &ps);
break;

//сообщение мыши
case WM_LBUTTONDOWN:

HDC hDC; //получаем контекст

hDC=GetDC(hWnd);

x=LOWORD(lParam);//координаты с которыми нажата мышь - аргументы WndProc
y=HIWORD(lParam);

//Если нажатие вписалось в координаты кнокпи
if((x>x1)&&(x<x2)&&(y>y1)&&(y<y2))
{
MessageBox(hWnd, "Поздравляю, с мышью вы разобрались!", "Yes-s-s!", MB_OK|MB_ICONINFORMATION);
}

break;

//сообщение выхода - разрушение окна
case WM_DESTROY:
DeleteObject(hBrush); //уничтожаем кисть
DeleteObject(hFont); //уничтожаем шрифт

PostQuitMessage(0); //Посылаем сообщение выхода с кодом 0 - нормальное завершение

break;

default:
return(DefWindowProc(hWnd, messg, wParam, lParam)); //освобождаем очередь приложения от нераспознаных
}
return 0;
}


Не стоит забывать о том, что надо после себя замести следы, уничтожив объекты шрифта и кисти и пера, чтобы те не оставались после завершения программы, замедляя систему. Для этого в теле сообщения WM_DESTROY мы уничтожим шрифт и кисть функцией DeleteObject.

DeleteObject(hBrush); //уничтожаем кисть
DeleteObject(hFont); //уничтожаем шрифт


Забавно иногда, когда контекст не уничтожен видеть, как прямо на Рабочем столе Windows вдруг всплывает эллипс красного цвета!

Назад Главная Вперёд