Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Программирование для IBM OS/2

© Александр Фролов, Григорий Фролов
Том 25, М.: Диалог-МИФИ, 1993, 286 стр.

[Назад] [Содеожание] [Дальше]

6.5. Приложение 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));
  }
}

Глобальные переменные

В переменные cxPoint и cyPoint записываются координаты курсора мыши в момент, когда пользователь начинает перемещение окна приложения, нажав левую кнопку мыши. Эти координаты будут затем сравниваться с координатами курсора мыши после завершения процесса перемещения, которые хранятся в переменных cxNewPoint и cyNewPoint.

Переменная fDrag используется в качестве признака перемещения окна и проверяется при обработке сообщения WM_MOUSEMOVE . Вначале в нее записывается значение FALSE. Когда пользователь начинает перемещать окно, это значение изменяется на TRUE. После завершения процесса перемещения в переменную снова записывается значение FALSE.

В области глобальных переменных мы также определили переменные hptr и hptr1 типа HPOINTER , в которых хранятся идентификаторы курсоров мыши, загруженных из ресурсов прложения. В первой из этих переменных хранится идентификатор курсора в виде открытой ладони, во второй - в виде закрытой ладони.

Функция main

В функции main нет ничего особенного за исключением того, что при создании главного окна приложения используется сокращенный набор флагов:

ULONG flFrameFlags = FCF_SIZEBORDER |
    FCF_SHELLPOSITION | FCF_TASKLIST | FCF_ICON;

В результате окно Frame Window не создает окна заголовка, системное меню и кнопки минимизации/максимизации. Без дополнительной обработки сообщений мыши пользователь не сможет перемещать такое окно. Размер окна можно изменять, так как указан флаг FCF_SIZEBORDER.

Функция окна WndProc

Функция окна обрабатывает сообщения WM_CREATE , WM_DESTROY , WM_BUTTON1DOWN , WM_BUTTON1UP , WM_MOUSEMOVE , WM_PAINT , WM_ERASEBACKGROUND , WM_SIZE и WM_BUTTON1DBLCLK .

Сообщение WM_CREATE

При создании окна обработчик сообщения WM_CREATE загружает из ресурсов приложения изображения курсоров мыши, пользуясь для этого функцией WinLoadPointer:

hptr  = WinLoadPointer(HWND_DESKTOP, NULLHANDLE, 
  ID_APP_POINTER);
hptr1 = WinLoadPointer(HWND_DESKTOP, NULLHANDLE, 
  ID_APP_POINTER1);

В качестве первого параметра функции передается идентификатор окна Desktop Window . Через второй параметр необходимо передать идентификатор модуля, содержащего соответствующий ресурс, или значение NULLHANDLE, если ресурс располагается в загрузочном файле приложения. Последний параметр предназначен для передачи идентификатора ресурса, с которым последний определен в файле описания ресурсов приложения.

Сообщение WM_DESTROY

В ответ на сообщение WM_DESTROY , которое передается в функцию окна при завершении работы приложения, выполняется уничтожение двух загруженных курсоров мыши при помощи функции WinDestroyPointer :

WinDestroyPointer (hptr);
WinDestroyPointer (hptr1);

В качестве единственного параметра этой функции передается идентификатор уничтожаемого курсора мыши.

Сообщение WM_SIZE

Обработчик сообщения WM_SIZE выполняет перерисовку окна приложения, когда пользователь изменяет его размеры, вызывая функцию WinInvalidateRect . В результате функция окна приложения получит сообщение WM_PAINT . Это необходимо для того чтобы строка символов всегда отображалась в центре окна.

Сообщение WM_PAINT

Обработчик сообщения WM_PAINT получает пространство отображения и затем определяет размеры окна, вызывая для этого функцию WinQueryWindow Rect. Далее с помощью функции WinDrawText в центре окна выводится текстовая строка, после чего пространство отображения освобождается.

Сообщение WM_BUTTON1DOWN

Когда пользователь начинает перемещение окна приложения MOUSEMOVE, он передвигает курсор мыши во внутреннюю область окна и нажимает левую клавишу мыши. При этом окно приложения получает сообщение WM_BUTTON1DOWN .

Обработчик этого сообщения запоминает координаты курсора мыши, соответствующие точке начала перемещения, в глобальных переменных cxPoint и cyPoint.

Далее окно выдвигается на передний план функцией WinSetWindowPos и устанавливается признак перемещения окна (в переменную fDrag записывается значение TRUE).

Сообщение WM_BUTTON1UP

После выполнения перемещения пользователь отпускает левую клавишу мыши. При этом в функцию окна приложения передается сообщение WM_BUTTON1UP . Обработчик этого сообщения просто сбрасывает признак перемещения окна, записывая в переменную fDrag значение FALSE.

Сообщение WM_MOUSEMOVE

Окно приложения получает сообщение WM_MOUSEMOVE всегда, когда над ним перемещается курсор мыши. Если пользователь нажал левую клавишу мыши и начал перемещение окна, обработчиком сообщения WM_BUTTON1UP устанавливается признак fDrag. В результате обработчик сообщения WM_MOUSEMOVE начинает процедуру перемещения окна.

Прежде всего он изменяет форму курсора мыши, вызывая функцию WinSetPointer :

WinSetPointer (HWND_DESKTOP, hptr1);

В качестве первого параметра этой функции передается идентификатор окна Desktop Window , а в качестве второго - идентификатор курсора мыши, который будет отображаться внутри окна.

На следующем шаге обработчик сообщения WM_MOUSEMOVE записывает новые координаты курсора в переменные cxNewPoint и cyNewPoint, а также определяет текущие координаты окна Frame Window , вызывая для этого функцию WinQueryWindow Pos.

Затем выполняется перемещение окна при помощи функции WinSetWindowPos :

WinSetWindowPos (hWndFrame, HWND_TOP ,
  swp.x + (cxNewPoint - cxPoint),
  swp.y + (cyNewPoint - cyPoint), 0, 0, SWP _MOVE );

Новые координаты окна выбираются исходя из текущих (записанных в структуре swp) и относительной величины смещения мыши по вертикали и горизонтали. Заметим, что функция WinQueryWindow Pos записывает в структуру swp координаты окна в системе координат, связанной с окном Desktop Window . Начало этой системы координат находится в левом нижнем углу экрана.

Если пользователь перемещает курсор мыши над окном приложения не нажимая левой клавиши мыши, обработчик сообщения WM_MOUSEMOVE отображает курсор мыши в виде открытой ладони:

WinSetPointer (HWND_DESKTOP, hptr);

Сообщение WM_BUTTON1DBLCLK

Так как окно приложения не имеет ни системного меню, ни меню верхнего уровня, для завершения его работы мы используем двойной щелчок левой клавишей мыши в окне приложения. Обработчик соответствующего сообщения WM_BUTTON1DBLCLK записывает в очередь приложения сообщение WM_QUIT , что приводит к завершению цикла обработки сообщений и прекращению работы приложения.

Файл mousemov.h

В файле mousemov.h определены символичесике константы для ресурсов приложения (листинг 6.2).

Листинг 6.2. Файл mousemov\mousemov.h

#define ID_APP_FRAMEWND 1
#define ID_APP_POINTER  2
#define ID_APP_POINTER1 3

Файл mousemov.rc

В файле описания ресурсов приложения mousemov.rc (листинг 6.3) помимо пиктограммы определены два указателя мыши, для чего использован оператор POINTER .

Листинг 6.3. Файл mousemov\mousemov.rc

#include <os2.h>
#include "mousemov.h"
ICON    ID_APP_FRAMEWND  MOUSEMOV.ICO
POINTER ID_APP_POINTER   MOUSEMOV.PTR
POINTER ID_APP_POINTER1  MOUSE1.PTR

Файл определения модуля mousemov.def

Файл определения модуля приложения представлен в листинге 6.4.

Листинг 6.4. Файл mousemov\mousemov.def

NAME        MOUSEMOV   WINDOWAPI
DESCRIPTION 'MouseMov Application (C) Frolov A., 1996'
HEAPSIZE    4096
STACKSIZE   32768
EXPORTS     WndProc
[Назад] [Содеожание] [Дальше]