Электронная библиотека книг Александра Фролова и Григория Фролова.
 
Библиотека
Братьев
Фроловых
Электронная библиотека книг Александра Фролова и Григория Фролова.
Библиотека системного программиста
Программирование на JAVA
ПК. Шаг за шагом
Другие книги
Восстановление данных
Антивирусная защита
Статьи для
программистов
Пользователю компьютера

Операционная система Microsoft Windows 3.1 для программиста. Дополнительные главы

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

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

1.8. Приложение MDITB

Приложение MDITB отличается от только что рассмотренного нами приложения MDIAPP наличием дополнительных окон Toolbar и Statusbar (рис. 1.11).

Рис. 1.11. Приложение MDITB

Для сокращения объема исходного текста мы не стали полностью реализовывать стандартные для окон Toolbar и Statusbar функции, ограничившись демонстрацией способов создания этих окон в MDI-приложении. Один из возможных способов реализации функций окна Toolbar мы описали в 13 томе "Библиотеки системного программиста" (см. разделы "Орган управления TOOLBAR" и "Приложение SMARTPAD" главы "Меню"). Реализация функций окна Statusbar не отнимет у вас много сил, поэтому вы справитесь с этим окном самостоятельно.

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


Листинг 1.5. Файл mditb/mditb.cpp


// ============================================================
// MDI-приложение с окнами Toolbar и Statusbar
// ============================================================
#define STRICT
#include <windows.h>
#include <mem.h>
#include "mditb.hpp"

BOOL InitApp(HINSTANCE);
LRESULT CALLBACK _export FrameWndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK _export ChildWndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK _export TbWndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK _export SbWndProc(HWND, UINT, WPARAM, LPARAM);

char const szFrameClassName[] = "MDITBAppClass";
char const szChildClassName[] = "MDITBChildAppClass";
char const szTbClassName[]    = "MDITBCtrlAppClass";
char const szSbClassName[]    = "MDISBCtrlAppClass";
char const szWindowTitle[]    = "MDI Application";

HINSTANCE hInst;
HWND hwndFrame;  // окно Frame Window
HWND hwndClient; // окно Client Window
HWND hwndChild;  // окно Child Window
HWND hwndTb;     // окно Toolbar
HWND hwndSb;     // окно Statusbar

// =====================================
// Функция WinMain
// =====================================
#pragma argsused
int PASCAL
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        LPSTR lpszCmdLine, int nCmdShow)
{
  MSG  msg;          // структура для работы с сообщениями
  hInst = hInstance; // сохраняем идентификатор приложения
  if(hPrevInstance)  // может быть запущена 
    return FALSE;    // только одна копия приложения
  if(!InitApp(hInstance))
      return FALSE;
  hwndFrame = CreateWindow(
    szFrameClassName,    // имя класса окна
    szWindowTitle,       // заголовок окна
    WS_OVERLAPPEDWINDOW, // стиль окна
    CW_USEDEFAULT, 0,    // задаем размеры и расположение
    CW_USEDEFAULT, 0,    // окна, принятые по умолчанию
    0,                   // идентификатор родительского окна
    0,                   // идентификатор меню
    hInstance,           // идентификатор приложения
    NULL);           // указатель на дополнительные параметры
  if(!hwndFrame)
    return FALSE;
  ShowWindow(hwndFrame, nCmdShow);
  UpdateWindow(hwndFrame);
  while(GetMessage(&msg, NULL, 0, 0))
  {
    if(!TranslateMDISysAccel(hwndClient, &msg))
    {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }
  }
  return msg.wParam;
}

// =====================================
// Функция InitApp
// Выполняет регистрацию класса окна
// =====================================
BOOL
InitApp(HINSTANCE hInstance)
{
  ATOM aWndClass; // атом для кода возврата
  WNDCLASS wc;    // структура для регистрации
                  // класса окна
  memset(&wc, 0, sizeof(wc));
  wc.lpszMenuName  = "APP_MENU";
  wc.style         = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc   = (WNDPROC)FrameWndProc;
  wc.cbClsExtra    = 0;
  wc.cbWndExtra    = 0;
  wc.hInstance     = hInstance;
  wc.hIcon         = LoadIcon(hInstance, "APP_ICON");
  wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
  wc.lpszClassName = (LPSTR)szFrameClassName;
  aWndClass = RegisterClass(&wc);

  if(!aWndClass)
    return FALSE;

  memset(&wc, 0, sizeof(wc));
  wc.lpszMenuName  = 0;
  wc.style         = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc   = (WNDPROC)ChildWndProc;
  wc.cbClsExtra    = 0;
  wc.cbWndExtra    = 0;
  wc.hInstance     = hInstance;
  wc.hIcon         = LoadIcon(hInstance, "APPCLIENT_ICON");
  wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  wc.lpszClassName = (LPSTR)szChildClassName;
  aWndClass = RegisterClass(&wc);

  if(!aWndClass)
    return FALSE;

  // Регистрируем класс для окна Toolbar
  memset(&wc, 0, sizeof(wc));
  wc.lpszMenuName  = 0;
  wc.style         = 0;
  wc.lpfnWndProc   = (WNDPROC)TbWndProc;
  wc.cbClsExtra    = 0;
  wc.cbWndExtra    = 0;
  wc.hInstance     = hInstance;
  wc.hIcon         = NULL;
  wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  wc.lpszClassName = (LPSTR)szTbClassName;
  aWndClass = RegisterClass(&wc);

  if(!aWndClass)
    return FALSE;

  // Регистрируем класс для окна Statusbar
  memset(&wc, 0, sizeof(wc));
  wc.lpszMenuName  = 0;
  wc.style         = 0;
  wc.lpfnWndProc   = (WNDPROC)SbWndProc;
  wc.cbClsExtra    = 0;
  wc.cbWndExtra    = 0;
  wc.hInstance     = hInstance;
  wc.hIcon         = NULL;
  wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  wc.lpszClassName = (LPSTR)szSbClassName;
  aWndClass = RegisterClass(&wc);

  if(!aWndClass)
    return FALSE;
  return TRUE;
}

// =====================================
// Функция FrameWndProc
// =====================================
LRESULT CALLBACK _export
FrameWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  CLIENTCREATESTRUCT clcs;
  MDICREATESTRUCT    mdics;
  switch (msg)
  {
    // Устанавливаем размеры окон Toolbar, Statusbar.
    // Уменьшаем размер окна Client Window
    case WM_SIZE:
    {
      // Располагаем окно Toolbar в верхней части
      // окна Frame Window
      MoveWindow(hwndTb,
        0,                      // x-координата
        0,                      // y-координата
        LOWORD(lParam),         // ширина
        TBAR_SIZE,              // высота
        TRUE);                  // требуется перерисовка окна

      // Располагаем окно Statusbar в нижней части
      // окна Frame Window
      MoveWindow(hwndSb,
        0,                           // x-координата
        HIWORD(lParam) - SBAR_SIZE,  // y-координата
        LOWORD(lParam),              // ширина
        SBAR_SIZE,                   // высота
        TRUE);                  // требуется перерисовка окна

      // Если окно не свернуто в пиктограмму и его
      // идентификатор отличен от нуля, вызываем
      // функцию MoveWindow
      if(wParam != SIZEICONIC && hwndClient)
      {
        MoveWindow(hwndClient,
          0,                      // x-координата
          TBAR_SIZE,              // y-координата
          LOWORD(lParam),         // ширина
          HIWORD(lParam) - (TBAR_SIZE + SBAR_SIZE), // высота
          TRUE);                  // требуется перерисовка окна

        // После уменьшения размеров окна нельзя
        // отдавать сообщение WM_SIZE функции DefFrameProc,
        // так как иначе размеры будут восстановлены
        return 0;
      }
      break;
    }

    case WM_CREATE:
    {
      clcs.hWindowMenu = GetSubMenu(GetMenu(hwnd), 1);
      clcs.idFirstChild = 500;
      
      // Создаем окно Client Window 
      hwndClient = CreateWindow(
        "MDICLIENT",    // имя класса окна
        NULL,           // заголовок окна
        WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | // стиль окна
          WS_HSCROLL | WS_VSCROLL,  
        0, 0, 0, 0,
        hwnd,           // идентификатор родительского окна
        (HMENU)1,       // идентификатор меню
        hInst,          // идентификатор приложения
        (LPSTR)&clcs);// указатель на дополнительные параметры

      // Создаем окно Toolbar
      hwndTb = CreateWindow(
        szTbClassName,  // имя класса окна
        NULL,           // заголовок окна
        WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | WS_DLGFRAME,
        0, 0, 0, 0,
        hwnd,           // идентификатор родительского окна
        (HMENU)2,       // идентификатор меню
        hInst,          // идентификатор приложения
        NULL);  // указатель на дополнительные параметры

      // Создаем окно Statusbar
      hwndSb = CreateWindow(
        szSbClassName,  // имя класса окна
        NULL,           // заголовок окна
        WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | WS_DLGFRAME,
        0, 0, 0, 0,
        hwnd,           // идентификатор родительского окна
        (HMENU)3,       // идентификатор меню
        hInst,          // идентификатор приложения
        NULL);  // указатель на дополнительные параметры

      break;
    }

    case WM_COMMAND:
    {
      switch (wParam)
      {
        case CM_FILENEW:
        {
          mdics.szClass = szChildClassName;   // класс окна
          mdics.szTitle = "MDI Child Window"; // заголовок окна
          mdics.hOwner  = hInst;   // идентификатор приложения 
          mdics.x       = CW_USEDEFAULT;  // размеры окна
          mdics.y       = CW_USEDEFAULT;  //   Document Window
          mdics.cx      = CW_USEDEFAULT;
          mdics.cy      = CW_USEDEFAULT;
          mdics.style   = 0;        // дополнительные стили
          mdics.lParam  = NULL;     // 32-битное значение

          // Посылаем сообщение WM_MDICREATE окну
          // Client Window. В результате будет создано новое 
          //  окно Document Window
          hwndChild = (HWND)SendMessage(hwndClient,
              WM_MDICREATE, 0, (LPARAM)&mdics);
          break;
        }

        case CM_WINDOWTILE:
        {
          SendMessage(hwndClient, WM_MDITILE, 0, NULL);
          break;
        }
        case CM_WINDOWCASCADE:
        {
          SendMessage(hwndClient, WM_MDICASCADE, 0, NULL);
          break;
        }
        case CM_WINDOWICONS:
        {
          SendMessage(hwndClient, WM_MDIICONARRANGE, 0, NULL);
          break;
        }
        case CM_WINDOWCLOSEALL:
        {
          HWND hwndTemp;
          ShowWindow(hwndClient, SW_HIDE);
          for(;;)
          {
            hwndTemp = GetWindow(hwndClient, GW_CHILD);
            if(!hwndTemp)
              break;
            while(hwndTemp && GetWindow(hwndTemp, GW_OWNER))
              hwndTemp = GetWindow(hwndTemp, GW_HWNDNEXT);
            if(hwndTemp)
              SendMessage(hwndClient, WM_MDIDESTROY, 
                  (WPARAM)hwndTemp, NULL);
            else
              break;
          }
          ShowWindow(hwndClient, SW_SHOW);
          break;
        }
        case CM_HELPABOUT:
        {
          MessageBox(hwnd,
            "Приложение MDIAPP\n(C) Фролов А.В., 1995",
             "Simple MDI Application",
             MB_OK | MB_ICONINFORMATION);
          break;
        }
        case CM_FILEEXIT:
        {
          DestroyWindow(hwnd);
          break;
        }
        default:
          break;
      }

      HWND hwndChild =
        (HWND)LOWORD(SendMessage(hwndClient, 
        WM_MDIGETACTIVE, 0, 0l));
      if(IsWindow(hwndChild))
        SendMessage(hwndChild, WM_COMMAND, wParam, lParam);
      return DefFrameProc(hwnd, hwndClient,
        msg, wParam, lParam);
    }
    case WM_DESTROY:
    {
      PostQuitMessage(0);
      break;
    }
    default:
      break;
  }
  return DefFrameProc(hwnd, hwndClient, msg, wParam, lParam);
}

// =====================================
// Функция ChildWndProc
// =====================================
LRESULT CALLBACK _export
ChildWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  HDC hdc;
  PAINTSTRUCT ps;
  RECT rc;
  switch (msg)
  {
    case WM_PAINT:
    {
      hdc = BeginPaint(hwnd, &ps);
      GetClientRect(hwnd, &rc);
      DrawText(hdc, "Child Window", -1, &rc,
        DT_SINGLELINE | DT_CENTER | DT_VCENTER);
      EndPaint(hwnd, &ps);
    }
    default:
      break;
  }
  return DefMDIChildProc(hwnd, msg, wParam, lParam);
}

// =====================================
// Функция TbWndProc
// =====================================
LRESULT CALLBACK _export
TbWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  HDC hdc;
  PAINTSTRUCT ps;
  RECT rc;
  switch (msg)
  {
    case WM_PAINT:
    {
      hdc = BeginPaint(hwnd, &ps);
      GetClientRect(hwnd, &rc);
      DrawText(hdc, "Toolbar Window", -1, &rc,
        DT_SINGLELINE | DT_CENTER | DT_VCENTER);
      EndPaint(hwnd, &ps);
    }
    default:
      break;
  }
  return DefMDIChildProc(hwnd, msg, wParam, lParam);
}

// =====================================
// Функция SbWndProc
// =====================================
LRESULT CALLBACK _export
SbWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  HDC hdc;
  PAINTSTRUCT ps;
  RECT rc;
  switch (msg)
  {
    case WM_PAINT:
    {
      hdc = BeginPaint(hwnd, &ps);
      GetClientRect(hwnd, &rc);
      DrawText(hdc, "Statusbar Window", -1, &rc,
        DT_SINGLELINE | DT_CENTER | DT_VCENTER);
      EndPaint(hwnd, &ps);
    }
    default:
      break;
  }
  return DefMDIChildProc(hwnd, msg, wParam, lParam);
}

На этапе инициализации приложения функция InitApp регистрирует классы для окон Frame Window, Document Window, а также для окон Toolbar и Statusbar. Эта процедура не имеет никаких особенностей. Отметим только, что вы можете изменить форму курсора мыши для окна Toolbar, указав нужный идентификатор курсора в поле hCursor структуры WNDCLASS перед регистрацией класса, или задать цвет окна Toolbar.

Окна Toolbar и Statusbar создаются в функции окна Frame Window при обработке сообщения WM_CREATE:

hwndTb = CreateWindow(
  szTbClassName,  // имя класса окна
  NULL,           // заголовок окна
  WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | WS_DLGFRAME,
  0, 0, 0, 0,
  hwnd,           // идентификатор родительского окна
  (HMENU)2,       // идентификатор меню
  hInst,          // идентификатор приложения
  NULL);  // указатель на дополнительные параметры
hwndSb = CreateWindow(
  szSbClassName,  // имя класса окна
  NULL,           // заголовок окна
  WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | WS_DLGFRAME,
  0, 0, 0, 0,
  hwnd,           // идентификатор родительского окна
  (HMENU)3,       // идентификатор меню
  hInst,          // идентификатор приложения
  NULL);  // указатель на дополнительные параметры

Обратите внимание, что для этих окон мы указали нулевые размеры, так как в момент их создания размеры внутренней области окна Frame Window еще неизвестны.

Вы можете указать для окон Toolbar и Statusbar любые стили, применимые к дочерним окнам. Для того чтобы эти окна появились на экране сразу после их создания, мы использовали стиль WS_VISIBLE.

Займемся теперь обработчиком сообщения WM_SIZE.

Прежде всего, он располагает окно Toolbar в верхней части внутренней области окна Frame Window, вызывая функцию MoveWindow:

MoveWindow(hwndTb,
  0,                      // x-координата
  0,                      // y-координата
  LOWORD(lParam),         // ширина
  TBAR_SIZE,              // высота
  TRUE);                  // требуется перерисовка окна

Координаты верхнего левого угла окна Toolbar устанавливаются равными значению (0,0), поэтому верхний левый угол этого окна совмещается с верхним левым углом внутренней области окна Frame Window.

Для определения ширины окна Toolbar анализируется параметр lParam, который для сообщения WM_SIZE равен ширине внутренней области окна.

Высота окна Toolbar в нашем приложении задается константой TBAR_SIZE, которая определена в файле mditb.hpp (листинг 1.6).

Аналогичным образом устанавливаются координаты и размеры окна Statusbar:

MoveWindow(hwndSb,
  0,                           // x-координата
  HIWORD(lParam) - SBAR_SIZE,  // y-координата
  LOWORD(lParam),              // ширина
  SBAR_SIZE,                   // высота
  TRUE);                  // требуется перерисовка окна

Высота окна Statusbar задается константой SBAR_SIZE.

Затем мы проверяем, создано ли окно Client Window, и не свернуто ли оно в пиктограмму. Если с окном все в порядке, устанавливаем для него новое расположение и размеры, оставляя место для окон Toolbar и Statusbar:

if(wParam != SIZEICONIC && hwndClient)
{
  MoveWindow(hwndClient,
    0,                      // x-координата
    TBAR_SIZE,              // y-координата
    LOWORD(lParam),         // ширина
    HIWORD(lParam) - (TBAR_SIZE + SBAR_SIZE), // высота
    TRUE);                  // требуется перерисовка окна
  return 0;
}
break;

Еще раз обращаем ваше внимание на то, что обработанное сообщение WM_SIZE нельзя отдавать функции DefFrameProc, поэтому после вызова функции MoveWindow мы выполняем возврат из функции окна оператором return.

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

В листинге 1.6 вы найдете файл mditb.hpp, содержащий определения констант для размеров окон Toolbar и Statusbar, а также для работы с меню.


Листинг 1.6. Файл mditb/mditb.hpp


#define TBAR_SIZE             35
#define SBAR_SIZE             35
#define CM_HELPABOUT          100
#define CM_FILEEXIT           101
#define CM_FILENEW            102
#define CM_WINDOWTILE         103
#define CM_WINDOWCASCADE      104
#define CM_WINDOWICONS        105
#define CM_WINDOWCLOSEALL     106

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


Листинг 1.7. Файл mditb/mditb.rc


#include "mditb.hpp"
APP_MENU MENU
BEGIN
        POPUP "&File"
        BEGIN
                MENUITEM "&New",   CM_FILENEW
                MENUITEM SEPARATOR
                MENUITEM "E&xit",  CM_FILEEXIT
        END
   POPUP "&Window"
   BEGIN
      MENUITEM    "&Tile",         CM_WINDOWTILE
      MENUITEM    "&Cascade",      CM_WINDOWCASCADE
      MENUITEM    "Arrange &Icons",CM_WINDOWICONS
      MENUITEM    "Close &All",    CM_WINDOWCLOSEALL
   END
        POPUP "&Help"
        BEGIN
                MENUITEM "&About...", CM_HELPABOUT
        END
END
APP_ICON ICON "mditb.ico"
APPCLIENT_ICON ICON "mditbcl.ico"

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


Листинг 1.8. Файл mditb/mditb.def


NAME        MDITB
DESCRIPTION 'Приложение MDITB, (C) 1995, Frolov A.V.'
EXETYPE     windows
STUB        'winstub.exe'
STACKSIZE   8120
HEAPSIZE    1024
CODE        preload moveable discardable
DATA        preload moveable multiple

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


Создание интернет-магазинов: http://www.shop2you.ru/ © Александр Фролов, Григорий Фролов, 1991-2016