Приложение MOUSEMOV
С помощью сообщения WM_MOUSEMOVE мы попробуем решить задачу перемещения окна приложения, не имеющего заголовка. Приложение MOUSEMOV создает окно без заголовка, системного меню и кнопок минимизации/максимизации, отображая в его центре текстовую строку (рис. 6.1).
Рис. 6.1. Окно приложения MOUSEMOV не имеет заголовка, но его можно перемещать при помощи мыши
Если в окне нажать левую клавишу мыши, то обрабатывая сообщение WM_MOUSEMOVE , приложение отслеживает текущие координаты мыши, передвигая соответствующим образом главное окно приложения Frame Window .
Когда курсор мыши оказывается над окном приложения MOUSEMOV, его форма изменяется - курсор принимает вид открытой ладони. Если нажать левую клавишу мыши, курсор будет изображаться в виде закрытой ладони. Внешне это выглядит так, как будто в процессе перемещения окна вы берете его рукой, переносите и затем отпускаете руку в нужном месте.
Рамка окна позволяет изменять размеры окна, причем текст отображается всегда в центре окна незвисимо от этих размеров.
Исходные тексты приложения MOUSEMOV приведены в листинге 6.1.
Листинг 6.1. Файл mousemov\mousemov.c
// ================================================= // Определения // =================================================
#define INCL_WIN #define INCL_GPI #define INCL_WINDIALOGS #include <os2.h> #include <stdio.h> #include "mousemov.h"
// Прототип функции окна приложения MRESULT EXPENTRY WndProc(HWND, ULONG, MPARAM, MPARAM);
// ================================================= // Глобальные переменные // =================================================
HAB hab; HWND hWndFrame; HWND hWndClient;
CHAR szAppTitle[] = "Mouse Mover";
// Координаты курсора мыши в момент нажатия // левой клавиши мыши SHORT cxPoint; SHORT cyPoint;
// Координаты курсора мыши в момент отпускания // левой клавиши мыши SHORT cxNewPoint; SHORT cyNewPoint;
// Признак начала процесса перемещения окна BOOL fDrag = FALSE;
// Текст, который будет отображаться в окне CHAR pszText[] = "Перемещайте окно при помощи левой клавиши мыши";
// Идентификаторы указателей мыши HPOINTER hptr, hptr1;
// ================================================= // Главная функция приложения main // =================================================
int main () { HMQ hmq; QMSG qmsg; BOOL fRc;
// Флаги для создания окна Frame Window // Мы не создаем окна заголовка, системного меню, // а также окна кнопок минимизации и максимизации ULONG flFrameFlags = FCF_SIZEBORDER | FCF_SHELLPOSITION | FCF_TASKLIST | FCF_ICON;
// Имя класса главного окна CHAR szWndClass[] = "MOUSEMOV";
hab = WinInitialize (0); if(hab == NULLHANDLE) { WinMessageBox (HWND_DESKTOP, HWND_DESKTOP, "Ошибка инициализации", "Ошибка", 0, MB_ICONHAND | MB_OK); return(-1); }
// Создаем очередь сообщений hmq = WinCreateMsgQueue (hab, 0); if(hmq == NULLHANDLE) { WinMessageBox (HWND_DESKTOP, HWND_DESKTOP, "Ошибка при создании очереди сообщений", "Ошибка", 0, MB_ICONHAND | MB_OK); WinTerminate (hab); return(-1); }
// Регистрация главного окна приложения fRc = WinRegisterClass (hab, szWndClass, (PFNWP)WndProc, 0, 0); if(fRc == FALSE) { WinMessageBox (HWND_DESKTOP, HWND_DESKTOP, "Ошибка при регистрации класса главного окна", "Ошибка", 0, MB_ICONHAND | MB_OK); WinDestroyMsgQueue (hmq); WinTerminate (hab);
return(-1); }
// Создаем главное окно приложения hWndFrame = WinCreateStdWindow (HWND_DESKTOP, WS_VISIBLE , &flFrameFlags, szWndClass, szAppTitle, 0, 0, ID_APP_FRAMEWND, &hWndClient); if(hWndFrame == NULLHANDLE) { WinMessageBox (HWND_DESKTOP, HWND_DESKTOP, "Ошибка при создании главного окна", "Ошибка", 0, MB_ICONHAND | MB_OK); WinDestroyMsgQueue (hmq); WinTerminate (hab);
return(-1); }
while(WinGetMsg (hab, &qmsg, 0, 0, 0)) WinDispatchMsg (hab, &qmsg);
WinDestroyWindow(hWndFrame); WinDestroyMsgQueue (hmq); WinTerminate (hab); return(0); }
// ================================================= // Функция главного окна приложения // =================================================
MRESULT EXPENTRY WndProc( HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2) { HPS hps; POINTL ptl; RECTL rec; SWP swp;
switch (msg) { // При создании окна загружаем указатели мыши case WM_CREATE : { hptr = WinLoadPointer(HWND_DESKTOP, NULLHANDLE, ID_APP_POINTER); hptr1 = WinLoadPointer(HWND_DESKTOP, NULLHANDLE, ID_APP_POINTER1); return FALSE; }
// При уничтожении окна удаляем указатели мыши case WM_DESTROY : { WinDestroyPointer (hptr); WinDestroyPointer (hptr1); return 0; }
// Когда пользователь нажимает левую клавишу // мыши, запоминаем координаты курсора и // выдвигаем окно приложения на передний план case WM_BUTTON1DOWN : { cxPoint = MOUSEMSG(&msg) -> x; cyPoint = MOUSEMSG(&msg) -> y;
// Изменяем расположение окна по оси Z WinSetWindowPos (hWndFrame, HWND_TOP , 0, 0, 0, 0, SWP _ZORDER );
// Устанавливаем признак перемещения // главного окна приложения fDrag = TRUE; return 0; }
// При отпускании левой клавиши мыши сбрасываем // признак перемещения окна case WM_BUTTON1UP : { // Сбрасываем признак перемещения // главного окна приложения fDrag = FALSE; return 0; }
// Это сообщение приходит при перемещении курсора // мыши case WM_MOUSEMOVE : { // Если включен признак перемещения, определяем // новые координаты курсора и передвигаем окно if(fDrag) { // Выбираем указатель в виде закрытой руки WinSetPointer (HWND_DESKTOP, hptr1);
cxNewPoint = MOUSEMSG(&msg) -> x; cyNewPoint = MOUSEMSG(&msg) -> y;
// Определяем текущие координаты окна WinQueryWindow Pos(hWndFrame, &swp);
// Передвигаем окно WinSetWindowPos (hWndFrame, HWND_TOP , swp.x + (cxNewPoint - cxPoint), swp.y + (cyNewPoint - cyPoint), 0, 0, SWP _MOVE ); }
else // Выбираем указатель в виде открытой руки WinSetPointer (HWND_DESKTOP, hptr);
return (MRESULT)TRUE; }
// В ответ на сообщение WM_PAINT выводим // в центре окна строку текста case WM_PAINT : { // Получаем пространство отображения hps = WinBeginPaint (hWnd, NULLHANDLE, &rec);
// Определяем размеры главного окна WinQueryWindow Rect(hWnd, &rec);
// Выводим текст в центре окна WinDrawText (hps, -1, pszText, &rec, 0L, 0L, DT_WORDBREAK | DT_CENTER | DT_VCENTER | DT_TEXTATTRS | DT_ERASERECT);
// Освобождаем пространство отображения WinEndPaint (hps); return 0; }
case WM_ERASEBACKGROUND : return(MRFROMLONG(1L));
// При изменении размеров окна сохраняем новые // размеры и перерисовываем окно case WM_SIZE : { // При изменении размеров окна выполняем его // перерисовку WinInvalidateRect (hWnd, NULL, TRUE); return 0; }
// Если пользователь сделал двойной щелчок левой // клавише мыши, завершаем работу приложения case WM_BUTTON1DBLCLK : { WinPostMsg (hWnd, WM_QUIT , 0L, 0L); return 0; }
default: return(WinDefWindowProc (hWnd, msg, mp1, mp2)); } }