КАК работает мышка в Win32 API?
С вашего позволения, начну этот раздел сразу же с примера. Наше окно будет реагировать на банальный щелчок по нему левой кнопкой. В ответ на это в том месте, где был сделан щелчок, будет появляться фраза: «Поздравляю, теперь вы умеет работать с мышью!». Так мы сразу убьём двух зайцев — научимся реагировать на мышь и узнавать в каком месте было сделано нажатие.
//Создаём прототип функции окна
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));
//сообщение выхода — разрушение окна
case WM_DESTROY:
PostQuitMessage(0); //Посылаем сообщение выхода с кодом 0 — нормальное завершение
break;
default:
return(DefWindowProc(hWnd, messg, wParam, lParam)); //освобождаем очередь приложения от нераспознаных
>
return 0;
>
Рассмотрим этот фрагмент более детально:
//Если был щелчок левой или правой кнопкой
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));
Получив сообщения от левой или правой кнопок мыши, окно запишет в переменную 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»;
//объявляем имя программы
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); //текст кнопки
//сообщение мыши
case WM_LBUTTONDOWN:
HDC hDC; //получаем контекст
x=LOWORD(lParam);//координаты с которыми нажата мышь — аргументы WndProc
y=HIWORD(lParam);
//Если нажатие вписалось в координаты кнокпи
if((x>x1)&&(x y1)&&(y
//сообщение выхода — разрушение окна
case WM_DESTROY:
DeleteObject(hBrush); //уничтожаем кисть
DeleteObject(hFont); //уничтожаем шрифт
PostQuitMessage(0); //Посылаем сообщение выхода с кодом 0 — нормальное завершение
default:
return(DefWindowProc(hWnd, messg, wParam, lParam)); //освобождаем очередь приложения от нераспознаных
>
return 0;
>
Не стоит забывать о том, что надо после себя замести следы, уничтожив объекты шрифта и кисти и пера, чтобы те не оставались после завершения программы, замедляя систему. Для этого в теле сообщения WM_DESTROY мы уничтожим шрифт и кисть функцией DeleteObject.
DeleteObject(hBrush); //уничтожаем кисть
DeleteObject(hFont); //уничтожаем шрифт
Забавно иногда, когда контекст не уничтожен видеть, как прямо на Рабочем столе Windows вдруг всплывает эллипс красного цвета!
Источник
Помогите с точными координатами курсора
Пишу программу для Windows, используя WinAPI и OpenGL.
Мне надо узнать координаты курсора в окне и для этого я использую функцию GetCursorPos. Но она выдаёт координаты отсчитывая их от левого нихнего угла. Мне надо отсчитывать от левого верхнего. Очевидно, нодо вычесть координату Y из высоты экрана, но тут такая проблема: сверху у окна заголовок высотой около 25 пикселей и он даёт искажения координаты.
В полноэкранном режиме ничего не мешает, но хочется, чтобы и в оконном всё было нормально. Короче, как узнать координату курсора в окне, независимо от его положения и размера границ?
И ещё как узнать разрешение, в котором находится монитор?
GetSystemMetrics
там и разрешение и высота заголовка и толщина рамки окна
ScreenToClient для конверта экранных координат в клиентскую область.
зы: от левого НИЖНЕГО это что-то новое. оно точно так у вас?
Спасибо, Дядя Саша.
А можно поподробнее об аргументе, а то у меня MSDN какой-то бедноватый, я в него уже и заглядывать перестал, а в яндексе всё одно и тоже и ничего подробного. Так что чувствую, что лучше спросить. Я так понял, что надо подставлять одну из SM_ констант.
Чем отличается SM_CXSCREEN от SM_CXFULLSCREEN?
И ещё GetSystemMetrics(SM_CXCURSOR) выдаёт что-то отличное от позиции курсора по X. Не знаю что именно она возвращает, но эффект другой, нежели от GetCursorPos.
Величина заголовка, как я понял это SM_CYCAPTION, тем более что он только для Y.
ap
>ScreenToClient для конверта экранных координат в клиентскую область.
>зы: от левого НИЖНЕГО это что-то новое. оно точно так у вас?
Ну не знаю как там, только менять приходится это точно. А целевая функция — gluUnProject;
ap
>ScreenToClient для конверта экранных координат в клиентскую область.
Как то странно она работает — я заметил отрицательные значения. Почему так?
Я пользуюсь GetCursorPos
при этом вычитая/прибавляя данные из:
SM_CXFRAME — толщина рамки
SM_CYFRAME — толщина рамки
SM_CYCAPTION — высота заголовка
для позицианирования окна:
SM_CXFULLSCREEN и SM_CYFULLSCREEN
чем отличается от SM_CXSCREEN я
не в курсе — мне и этого хватает. 🙂
я сделал стандартный c++ win32 проект и в цикле обработки сообщений добавил
Zefick
ЬЫВТ: Note, a screen-coordinate point that is above the window’s client area has a negative y-coordinate. Similarly, a screen coordinate to the left of a client area has a negative x-coordinate.
правка: это по поводу отрицательных координат после ScreenToClient
ap
убери эти «+3», «-3».
3 — это ширина бордера окна в твоих настройках Windows.
Кроме, того, там есть хитрости, связанные с тем, что окно бывает разных типов:
— оно может быть fixed size (у окон, размер которого меняется, в принципе, ширина бордера можжет отличаться, от окна, размер которого не меняется),
— оно может быть tool (у таких окон, высота кэпшена меньше),
— оно может быть popup (нет ни бордера, ни капшена)
Demiurg-HG
довольно обидны ваши слова 🙂 это просто радиусы эллипса чтобы нарисовать кружочек в месте курсора 🙂 ScreenToClient учитывает все вышеперечисленное
Ещё однин вопрос не по теме. Я заметил, что у MessageBox’а в зависимости от последнего параметра разные стили. Если MB_OK, то текущий стиль Windows, а если, скажем MB_DEFAULT_DESKTOP_ONLY, то классический стиль. От чего это зависит?
Zefick
Последний параметр MessageBox может быть or комбинацией разных флагов, одни из которых управляют кнопками, другие иконками, остальные прочими поведенческими особенностями (хочеш знать все стили без документации — встань в коде в студии курсором на MB_DEFAULT_DESKTOP_ONLY, нажми волшебный ф12 и он бросит тебя прямо в winuser где сидят все MB_).
Определение MB_DEFAULT_DESKTOP_ONLY — The desktop currently receiving input must be a default desktop; otherwise, the function fails. A default desktop is one an application runs on after the user has logged on. Смысл этого предложения для меня неясен 🙂 Моя виста такие окошки не кажет 🙂
ap
Ох, сорри.. 🙁
Пару дней назад как раз с аналогичной проблемой парился, т.е. GetSystemMetrics работал, а вот приходилось учитывать все это дело для разных стилей.
Я понял, что ScreenToClient надо использовать не вместо GetCursorPos, а вместе с ним. Так вроде все нормально.
ap
>хочеш знать все стили без документации — встань в коде в студии
>курсором на MB_DEFAULT_DESKTOP_ONLY, нажми волшебный ф12 и он бросит тебя прямо
>в winuser где сидят все MB_).
Ух ты! Вообще я использую нажатие правой кнопки мыши на переменной а затем
Go To Definition, но теперь буду использовать и этот метод.
Источник
Определить координаты мышки в момент клика (в консоли)
Нужно определить координаты мышки в момент клика(в консоли).
Консоль изначально открыта на полный экран без рамки.
Есть условная функция в которая при нажатии мышки должна возвращать координаты
Заранее спасибо
Добавлено через 24 минуты
UPD: координаты курсора уже получаю, осталось лишь ловить нажатие ЛКМ
Помощь в написании контрольных, курсовых и дипломных работ здесь.
Координаты клика мышки
Всем привет.Нужно в программе в поле объекта TImage получить координаты клика мышки.Можно ли это.
Изменить координаты клика мышки
Есть монитор 19 дюймов, нанего прицепили сверху тачпад но уже 22 дюйма, и когда пытаешся отрыть.
Перемещение элемента в координаты клика мышки
Здравствуйте. Моя задача переместить элемент в координаты клика мышки. Т.е. пользователь кликает.
Как при клики мышкой по TabControl1 вывести координаты клика мышки
Имеется процедура ‘при нажатии на кнопку миши дает ее координаты Private Sub.
Определить координаты мышки
Друзья, мне нужно на сайт простенькую штуку. Есть панель=окно, в нее вставлена картинка. нужен.
Определить координаты клика мыши
Всем привет, помогите , пожалуйста разобраться. Есть picturebox в который загружается изображение с.
Определить какая клавиша была зажата на клавиатуре в момент клика мышью по контроллу
Приветствую всех! Суть вопроса такова — есть DataGridView. Необходимо определить какая клавиша.
Как определить координаты клика в PictureBox?
Добрый день. Есть на форме Picturebox. После клика по этому пиктурбоксу каким образом определить.
Выводить координаты мышки по срабатыванию любой кнопки мышки каждый раз разными цветами
Здравствуйте , никак не могу разобраться в задании , необходимо выводить координаты мышки по.
Определить координаты центра консоли
Всем привет, есть задача — нарисовать квадрат в центре консоли, а потом его увеличивать постепенно.
Источник