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

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

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

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

2.5. Приложение WINTREE

Наше следующее приложение называется WINTREE. Оно создает два окна верхнего уровня и одно дочернее окно (рис. 2.1), демонстрируя древовидную структуру родительских отношений между окнами.

Рис. 2.1. Окна, создаваемые приложением WINTREE

Изучая это приложение, вы научитесь создавать дочерние окна, а также сможете изучить поведение таких окон, сравнив их с поведением окон верхнего уровня.

Исходный текст приложения WINTREE показан в листинге 2.1.

Листинг 2.1. Файл wintree\wintree.c

// ===================================================
// Определения
// ===================================================

#define INCL_WIN
#define INCL_GPI
#define INCL_WINDIALOGS
#include <os2.h>
#include <stdio.h>
#include "wintree.h"

// Прототип функции окна приложения
MRESULT EXPENTRY WndProc1(HWND, ULONG, MPARAM, MPARAM);
MRESULT EXPENTRY WndProc2(HWND, ULONG, MPARAM, MPARAM);
MRESULT EXPENTRY 
  WndProcChild(HWND, ULONG, MPARAM, MPARAM);

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

// Идентификатор Anchor-block
HAB  hab;

// Идентификатор первого и второго окна Frame Window 
HWND hWndFrame1;
HWND hWndFrame2;

// Идентификатор дочернего окна
HWND hWndChildFrame;

// Идентификатор первого и второго окна Client Window 
HWND hWndClient1;
HWND hWndClient2;

// Идентификатор окна Client Window  дочернего окна
HWND hWndChildClient;

// Заголовки окон
CHAR szAppTitle1[]  = "Windows Tree Demo 1";
CHAR szAppTitle2[]  = "Windows Tree Demo 2";
CHAR szChildTitle[] = "Child Window";

// ===================================================
// Главная функция приложения main 
// Получает управление при запуске приложения
// ===================================================

int main ()
{
  HMQ   hmq;
  QMSG   qmsg;
  BOOL  fRc;

  // Флаги для создания окна Frame Window 
  ULONG flFrameFlags =
    FCF_SYSMENU    | FCF_TITLEBAR       | FCF_MINMAX   |
    FCF_SIZEBORDER | FCF_SHELLPOSITION | FCF_TASKLIST |
    FCF_ICON;

  // Флаги для создания дочернего окна
  ULONG flFrameChildFlags =
    FCF_SYSMENU    | FCF_TITLEBAR       | FCF_MINMAX   |
    FCF_SIZEBORDER;

  // Имена классов для создаваемых окон
  CHAR  szWndClass1[] = "WINTREE1";
  CHAR  szWndClass2[] = "WINTREE2";
  CHAR  szWndClassChild[] = "WINTREECHILD";

  // Инициализация приложения
  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, szWndClass1, 
     (PFNWP)WndProc1, 0, 0);

  if(fRc == FALSE)
  {
    WinMessageBox (HWND_DESKTOP, HWND_DESKTOP,
      "Ошибка при регистрации класса главного окна",
      "Ошибка", 0, MB_ICONHAND | MB_OK);
    WinDestroyMsgQueue (hmq);
    WinTerminate (hab);

    return(-1);
  }

  // Регистрация класса второго окна
  fRc = WinRegisterClass (hab, szWndClass2,
    (PFNWP)WndProc2, 0, 0);

  if(fRc == FALSE)
  {
    WinMessageBox (HWND_DESKTOP, HWND_DESKTOP,
      "Ошибка при регистрации класса главного окна",
      "Ошибка", 0, MB_ICONHAND | MB_OK);
    WinDestroyMsgQueue (hmq);
    WinTerminate (hab);

    return(-1);
  }

  // Регистрация класса дочернего окна
  fRc = WinRegisterClass (hab, szWndClassChild,
    (PFNWP)WndProcChild, 0, 0);

  if(fRc == FALSE)
  {
    WinMessageBox (HWND_DESKTOP, HWND_DESKTOP,
      "Ошибка при регистрации класса главного окна",
      "Ошибка", 0, MB_ICONHAND | MB_OK);
    WinDestroyMsgQueue (hmq);
    WinTerminate (hab);

    return(-1);
  }

  // Создаем главное окно приложения
  hWndFrame1 = WinCreateStdWindow (HWND_DESKTOP,
    WS_VISIBLE ,
    &flFrameFlags, szWndClass1, szAppTitle1,
    0, 0, ID_APP_FRAMEWND, &hWndClient1);

  if(hWndFrame1 == NULLHANDLE)
  {
    WinMessageBox (HWND_DESKTOP, HWND_DESKTOP,
      "Ошибка при создании главного окна",
      "Ошибка", 0, MB_ICONHAND | MB_OK);

    WinDestroyMsgQueue (hmq);
    WinTerminate (hab);

    return(-1);
  }

  // Создаем второе окно
  hWndFrame2 = WinCreateStdWindow  (HWND_DESKTOP,
    WS_VISIBLE ,
    &flFrameFlags, szWndClass2, szAppTitle2,
    0, 0, ID_APP_FRAMEWND, &hWndClient1);

  if(hWndFrame2 == NULLHANDLE)
  {
    WinMessageBox (HWND_DESKTOP, HWND_DESKTOP,
      "Ошибка при создании второго окна",
      "Ошибка", 0, MB_ICONHAND | MB_OK);

    WinDestroyWindow(hWndFrame1);
    WinDestroyMsgQueue (hmq);
    WinTerminate (hab);

    return(-1);
  }

  // Создаем дочернее окно
  hWndChildFrame = WinCreateStdWindow (hWndFrame2, 
    WS_VISIBLE ,
    &flFrameChildFlags, szWndClassChild, szChildTitle,
    0, 0, ID_CHILDWND, &hWndChildClient);

  if(hWndChildFrame == NULLHANDLE)
  {
    WinMessageBox (HWND_DESKTOP, HWND_DESKTOP,
      "Ошибка при создании дочернего окна",
      "Ошибка", 0, MB_ICONHAND | MB_OK);

    WinDestroyWindow(hWndFrame2);
    WinDestroyWindow(hWndFrame1);
    WinDestroyMsgQueue (hmq);
    WinTerminate (hab);

    return(-1);
  }

  // Устанавливаем начальные размеры и
  // расположение дочернего окна
  WinSetWindowPos (hWndChildFrame, HWND_TOP , 
    10, 10, 200, 200,
    SWP _ACTIVATE  | SWP_SIZE  | SWP_SHOW  | SWP_MOVE );

  // Устанавливаем пиктограмму для дочернего окна
  WinSendMsg (hWndChildFrame, WM_SETICON ,
    (MPARAM)WinQuerySysPointer (HWND_DESKTOP,
    SPTR_APPICON, FALSE), NULL);

  // Запускаем цикл обработки сообщений
  while(WinGetMsg (hab, &qmsg, 0, 0, 0))
    WinDispatchMsg (hab, &qmsg);

  // Уничтожаем главное окно приложения
  WinDestroyWindow(hWndFrame1);

  // Удаляем очередь сообщений и вызываем
  // функцию WinTerminate 
  WinDestroyMsgQueue (hmq);
  WinTerminate (hab);

  // Возвращаем управление операционной системе
  return(0);
}

// ==================================================
// Функция главного окна приложения
// ==================================================

MRESULT EXPENTRY
WndProc1(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
  CHAR szMsg[100];

  switch (msg)
  {
    case WM_ERASEBACKGROUND :
      return(MRFROMLONG(1L));

    case WM_BUTTON1DOWN :
    {
      sprintf (szMsg, "(x, y) = (%ld, %ld)",
        SHORT1FROMMP (mp1), SHORT2FROMMP (mp1));

      WinMessageBox (HWND_DESKTOP, hWnd,  szMsg,
        "Координаты курсора мыши (окно 1)",
        0, MB_INFORMATION | MB_OK);
    }

    default:
      return(WinDefWindowProc (hWnd, msg, mp1, mp2));
  }
}

// ==================================================
// Функция второго окна приложения
// ==================================================

MRESULT EXPENTRY
WndProc2(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
  CHAR szMsg[100];

  switch (msg)
  {
    case WM_ERASEBACKGROUND :
      return(MRFROMLONG(1L));

    case WM_BUTTON1DOWN :
    {
      sprintf (szMsg, "(x, y) = (%ld, %ld)",
        SHORT1FROMMP (mp1), SHORT2FROMMP (mp1));

      WinMessageBox (HWND_DESKTOP, hWnd,  szMsg,
        "Координаты курсора мыши (окно 2)",
        0, MB_INFORMATION | MB_OK);
    }

    default:
      return(WinDefWindowProc (hWnd, msg, mp1, mp2));
  }
}

// ==================================================
// Функция дочернего окна
// ==================================================

MRESULT EXPENTRY
WndProcChild(HWND hWnd, ULONG msg, 
  MPARAM mp1, MPARAM mp2)
{
  CHAR szMsg[100];

  switch (msg)
  {
    case WM_ERASEBACKGROUND :
      return(MRFROMLONG(1L));

    case WM_BUTTON1DOWN :
    {
      sprintf (szMsg, "(x, y) = (%ld, %ld)",
        SHORT1FROMMP (mp1), SHORT2FROMMP (mp1));

      WinMessageBox (HWND_DESKTOP, hWnd,  szMsg,
        "Координаты курсора мыши (дочернее окно)",
        0, MB_INFORMATION | MB_OK);
    }

    default:
      return(WinDefWindowProc (hWnd, msg, mp1, mp2));
  }
}

Файл wintree.h

Файл wintree.h, приведенный в листинге 2.2, содержит определение констант ID_APP_FRAMEWND и ID_CHILDWND (идентификаторы ресурсов для окон верхнего уровня и дочернего окна).

Листинг 2.2. Файл wintree\wintree.h

#define ID_APP_FRAMEWND 1
#define ID_CHILDWND     2

Файл wintree.rc

Файл описания ресурсов приложения (листиг 2.3) содержит определение пиктограммы.

Листинг 2.3. Файл wintree\wintree.rc

#include <os2.h>
#include "wintree.h"
ICON ID_APP_FRAMEWND WINTREE.ICO

Файл wintree.def

В файле определения модуля (листинг 2.4) в секции EXPORTS перечислены имена всех функций обратного вызова. В роли этих функций выступают функции окон верхнего уровня WndProc1 и WndProc2, а также функция дочернего окна WndProcChild.

Листинг 2.4. Файл wintree\wintree.def

NAME        WINTREE   WINDOWAPI
DESCRIPTION 'WinTree Application (C) Frolov A., 1996'
HEAPSIZE    4096
STACKSIZE   32768
EXPORTS     WndProc1
            WndProc2
            WndProcChild

Определения

В самом начале исходного текста приложения определены три прототипа функций окна. Две из этих функций соответствуют окнам верхнего уровня, одна - дочернему окну.

Для каждого из перечисленных выше трех окон в области глобальных переменных хранятся идентификаторы окна Frame Window (hWndFrame1, hWndFrame2 и hWndChildFrame), а также идентификаторы окон Client Window (hWndClient1, hWndClient2 и hWndChildClient).

Кроме этого, в области глобальных переменных находятся заголовки для создаваемых окон (szAppTitle1, szAppTitle2 и szChildTitle).

Функция main

В функции main определены флаги, которые используются для создания окон верхнего уровня (переменная flFrameFlags) и для окна дочернего уровня (переменная flFrameChildFlags).

Обратите внимание, что для дочернего окна мы не используем флаги FCF_ICON , FCF_SHELLPOSITION и FCF_TASKLIST . Для установки пиктограммы, отображемой в верхнем левом углу дочернего окна, мы посылаем этому окну сообщение WM_SETICON . Размеры и расположение дочернего окна будут установлены явням образом при помощи функции WinSetWindowPos .

Каждое из трех окон нашего приложения имеет свою функцию окна и потому создается на базе своего класса окна. Имена этих классов хранятся в переменных szWndClass1, szWndClass2 и szWndClassChild.

Свою работу функция main начинает, как обычно, с вызова функции инициализации WinInitialize . Далее при помощи функции WinCreateMsgQueue создается очередь сообщений.

После этого для регистрации классов окна три раза вызывается функция WinRegisterClass . При этом определяется, что для окон, создаваемых на базе класса szWndClass1, будет использоваться функция окна WndProc1, для окон, создаваемых на базе класса szWndClass2 - функция окна WndProc2, а для окон, создаваемых на базе класса szWndClassChild - функция окна WndProcChild.

Как и раньше, после вызова каждой функции проверяется код возврата. Если при выполнении функции произошла ошибка, приложение выводит на экран соответствующее сообщение и завершает свою работу.

Если регистрация классов завершилась успешно, функция main создает два окна верхнего уровня, аналогично тому, как создавалось главное окно предыдущего приложения. Каждое из этих окон основано на базе своего класса окна и имеет собственную функцию окна, однако для обоих окон мы указали один и тот же идентификатор ресурсов. В результате эти окна будут иметь одинаковую пиктограмму системного меню.

На следующем этапе наше приложение создает окно, которое является дочерним по отношению к второму окну верхнего уровня, имеющему идентификатор hWndFrame2. Для этого используется знакомая вам функция WinCreateStdWindow :

hWndChildFrame = WinCreateStdWindow (hWndFrame2, 
  WS_VISIBLE ,
  &flFrameChildFlags, szWndClassChild, szChildTitle,
  0, 0, ID_CHILDWND, &hWndChildClient);

В качестве идентификатора ресурса для дочернего окна указана константа ID_CHILDWND. В файле описания ресурсов нет пиктограммы с таким идентификатором, поэтому если не предпринимать никаких дополнительных мер, для системного меню будет использована стандартная пиктограмма, определенная в Presentation Manager.

После создания дочернего окна функция main устанавливает его размеры и расположение, вызывая для этого рассмотренную нами ранее функцию WinSetWindowPos :

WinSetWindowPos (hWndChildFrame, HWND_TOP , 
  10, 10, 200, 200,
  SWP _ACTIVATE  | SWP_SIZE  | SWP_SHOW  | SWP_MOVE );

Далее для изменения пиктограммы системного меню при помощи функции WinSendMsg в функцию дочернего окна посылается сообщение WM_SETICON :

WinSendMsg (hWndChildFrame, WM_SETICON ,
  (MPARAM)WinQuerySysPointer (HWND_DESKTOP,
  SPTR_APPICON, FALSE), NULL);

Первый параметр этого сообщения должен содержать идентификатор пиктограммы, второй не используется и указан как NULL.

Функция WinQuerySysPointer предназначена для получения идентификатора ресурса системного курсора или системной пиктограммы, заданной своим идентификатором. Прототип этой функции приведен ниже:

HPOINTER WinQuerySysPointer (
  HWND hwndDeskTop, // идентификатор окна Desktop Window 
  LONG lIdentifier, // идентификатор системного курсора
                    // или пиктограммы
  BOOL fCopy);      // признак копирования

В качестве значения для параметра hwndDeskTop можно использовать константу HWND_DESKTOP. Что же касается идентификатора lIdentifier, то для него следует указывать одно из приведенных ниже значений.

Значение Описание
SPTR_ARROW Курсор в виде стрелки
SPTR_TEXT Текстовый курсор в виде буквы I
SPTR_WAIT Курсор в виде песочных часов
SPTR_SIZE Курсор для изменения размера
SPTR_MOVE Курсор для перемещения объектов
SPTR_SIZENWSE Курсор для изменения размера, направленный вниз
SPTR_SIZENESW Курсор для изменения размера, направленный вверх
SPTR_SIZEWE Горизонтальный курсор для изменения размера
SPTR_SIZENS Вертикальный курсор для изменения размера
SPTR_APPICON Стандартная пиктограмма приложения
SPTR_ICONINFORMATION Пиктограмма для информационного сообщения
SPTR_ICONQUESICON Пиктограмма со знаком вопроса
SPTR_ICONERROR Пиктограмма для сообщения об ошибке
SPTR_ICONWARNING Пиктограмма для предупреждающего сообщения
SPTR_ILLEGAL Пиктограмма для сообщения о неправильной операции
SPTR_FILE Пиктограмма для обозначения одного файла
SPTR_MULTFILE Пиктограмма для обозначения группы файлов
SPTR_FOLDER Пиктограмма папки
SPTR_PROGRAM Пиктограмма приложения

Признак копирования fCopy может принимать значения TRUE или FALSE. В первом случае создается копия указанного системного ресурса, которая при необходимости может быть модифицирована. Ресурс, созданный таким образом, должен быть удален после использования при помощи функции WinDestroyPointer . Эта функция имеет единественный параметр - идентификатор уничтожаемого ресурса.

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

Функции окон

Функции окон, определенные в нашем приложении, похожи друг на друга и на функцию окна из предыдущего приложения. Их основная работа заключается в том, чтобы выводить на экран сообщение, когда пользователь делает щелчок левой клавишей мыши в области окна. В сообщении указывается название окна и координаты курсора мыши (в системе координат, связанной с этим окном).

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