Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Programming_Windows_95_Part_II.pdf
Скачиваний:
41
Добавлен:
05.06.2014
Размер:
3.02 Mб
Скачать

159

Для поддержки MDI в Windows 95 имеется один класс окна, пять функций, две структуры данных и двенадцать сообщений. О классе окна MDICLIENT и структурах данных CLIENTCREATESTRUCT и MDICREATESTRUCT

уже упоминалось. Две из пяти функций заменяют в приложениях MDI функцию DefWindowProc: вместо вызова функции DefWindowProc для всех необрабатываемых сообщений, оконная процедура главного окна вызывает функцию DefFrameProc, а оконная процедура дочернего окна вызывает функцию DefMDIChildProc. Другая характерная функция MDI TranslateMDISysAccel используется также, как функция TranslateAccelerator, о которой рассказывалось в главе 10. В Windows 3 добавлена функция ArrangeIconicWindows, но одно из специальных сообщений MDI делает ее использование не нужным в программах MDI.

Если в дочерних окнах MDI выполняются какие-то протяженные во времени операции, рассмотрите возможность их запуска в отдельных потоках. Это позволит пользователю покинуть "задумавшееся" дочернее окно и продолжить работу в другом окне, пока первое дочернее окно решает свою задачу в фоновом режиме. В Windows 95 специально для этой цели имеется новая функция CreateMDIWindow. Поток вызывает функцию CreateMDIWindow для создания дочернего окна MDI; таким образом окно действует исключительно внутри контекста потока. В программе, имеющей один поток, для создания дочернего окна функция CreateMDIWindow не требуется, поскольку то же самое выполняет сообщение WM_MDICREATE.

Подошло время для примера однопотоковой программы, в которой будет показано девять из двенадцати сообщений MDI. (Оставшиеся три обычно не требуются.) Эти сообщения имеют префикс WM_MDI. Главное окно посылает одно из этих сообщений окну-администратору для выполнения какой-либо операции над дочерним окном или для получения информации о дочернем окне. (Например, главное окно посылает сообщение WM_MDICREATE окну-администратору для создания дочернего окна.) Исключение составляет сообщение WM_MDIACTIVATE: в то время, как главное окно может послать это сообщение окну-администратору для активизации одного из дочерних окон, окно-администратор также посылает сообщение тем дочерним окнам, которые будут активизированы и тем, которые потеряют активность, чтобы проинформировать их о предстоящем изменении.

Пример программы

Программа MDIDEMO, представленная на рис. 18.2, иллюстрирует основы написания приложения MDI.

MDIDEMO.MAK

#------------------------

# MDIDEMO.MAK make file

#------------------------

mdidemo.exe : mdidemo.obj mdidemo.res

$(LINKER) $(GUIFLAGS) -OUT:mdidemo.exe mdidemo.obj mdidemo.res $(GUILIBS)

mdidemo.obj : mdidemo.c mdidemo.h $(CC) $(CFLAGS) mdidemo.c

mdidemo.res : mdidemo.rc mdidemo.h $(RC) $(RCVARS) mdidemo.rc

MDIDEMO.C

/*--------------------------------------------------------

 

MDIDEMO.C --

Multiple Document Interface Demonstration

 

(c) Charles Petzold, 1996

--------------------------------------------------------

*/

#include <windows.h> #include <stdlib.h> #include "mdidemo.h"

LRESULT CALLBACK FrameWndProc (HWND, UINT, WPARAM, LPARAM);

BOOL CALLBACK CloseEnumProc(HWND, LPARAM);

LRESULT CALLBACK HelloWndProc (HWND, UINT, WPARAM, LPARAM);

LRESULT CALLBACK RectWndProc (HWND, UINT, WPARAM, LPARAM);

// structure for storing data unique to each Hello child window

typedef struct tagHELLODATA

{

UINT iColor;

160

COLORREF clrText;

}

HELLODATA, *LPHELLODATA;

// structure for storing data unique to each Rect child window

typedef struct tagRECTDATA

{

short cxClient; short cyClient;

}

RECTDATA, *LPRECTDATA;

// global variables

char

szFrameClass[]

=

"MdiFrame";

char

szHelloClass[]

=

"MdiHelloChild";

char

szRectClass[]

= "MdiRectChild";

HINSTANCE

hInst;

 

 

HMENU

hMenuInit, hMenuHello, hMenuRect;

HMENU

hMenuInitWindow, hMenuHelloWindow, hMenuRectWindow;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)

{

 

HACCEL

hAccel;

HWND

hwndFrame, hwndClient;

MSG

msg;

WNDCLASSEX

wndclass;

hInst = hInstance;

if(!hPrevInstance)

{

// Register the frame window class

wndclass.cbSize

= sizeof(wndclass);

wndclass.style

= CS_HREDRAW | CS_VREDRAW;

wndclass.lpfnWndProc

= FrameWndProc;

wndclass.cbClsExtra

= 0;

wndclass.cbWndExtra

= 0;

wndclass.hInstance

= hInstance;

wndclass.hIcon

= LoadIcon(NULL, IDI_APPLICATION);

wndclass.hCursor

= LoadCursor(NULL, IDC_ARROW);

wndclass.hbrBackground

=(HBRUSH)(COLOR_APPWORKSPACE + 1);

wndclass.lpszMenuName

= NULL;

wndclass.lpszClassName

= szFrameClass;

wndclass.hIconSm

= LoadIcon(NULL, IDI_APPLICATION);

RegisterClassEx(&wndclass);

// Register the Hello child window class

wndclass.cbSize

= sizeof(wndclass);

wndclass.style

= CS_HREDRAW | CS_VREDRAW;

wndclass.lpfnWndProc

= HelloWndProc;

wndclass.cbClsExtra

= 0;

wndclass.cbWndExtra

= sizeof(HANDLE);

wndclass.hInstance

= hInstance;

wndclass.hIcon

= LoadIcon(NULL, IDI_APPLICATION);

wndclass.hCursor

= LoadCursor(NULL, IDC_ARROW);

wndclass.hbrBackground

=(HBRUSH) GetStockObject(WHITE_BRUSH);

wndclass.lpszMenuName

= NULL;

wndclass.lpszClassName

= szHelloClass;

wndclass.hIconSm

= LoadIcon(NULL, IDI_APPLICATION);

161

RegisterClassEx(&wndclass);

// Register the Rect child window class

wndclass.cbSize

= sizeof(wndclass);

wndclass.style

= CS_HREDRAW | CS_VREDRAW;

wndclass.lpfnWndProc

= RectWndProc;

wndclass.cbClsExtra

= 0;

wndclass.cbWndExtra

= sizeof(HANDLE);

wndclass.hInstance

= hInstance;

wndclass.hIcon

= LoadIcon(NULL, IDI_APPLICATION);

wndclass.hCursor

= LoadCursor(NULL, IDC_ARROW);

wndclass.hbrBackground

=(HBRUSH) GetStockObject(WHITE_BRUSH);

wndclass.lpszMenuName

= NULL;

wndclass.lpszClassName

= szRectClass;

wndclass.hIconSm

= LoadIcon(NULL, IDI_APPLICATION);

RegisterClassEx(&wndclass);

}

// Obtain handles to three possible menus & submenus

hMenuInit = LoadMenu(hInst, "MdiMenuInit");

hMenuHello = LoadMenu(hInst, "MdiMenuHello");

hMenuRect = LoadMenu(hInst, "MdiMenuRect");

hMenuInitWindow = GetSubMenu(hMenuInit, INIT_MENU_POS);

hMenuHelloWindow = GetSubMenu(hMenuHello, HELLO_MENU_POS);

hMenuRectWindow = GetSubMenu(hMenuRect, RECT_MENU_POS);

// Load accelerator table

hAccel = LoadAccelerators(hInst, "MdiAccel");

// Create the frame window

hwndFrame = CreateWindow(szFrameClass, "MDI Demonstration", WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

NULL, hMenuInit, hInstance, NULL);

hwndClient = GetWindow(hwndFrame, GW_CHILD); ShowWindow(hwndFrame, iCmdShow); UpdateWindow(hwndFrame);

// Enter the modified message loop

while(GetMessage(&msg, NULL, 0, 0))

{

if(!TranslateMDISysAccel(hwndClient, &msg) &&

!TranslateAccelerator(hwndFrame, hAccel, &msg))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

}

// Clean up by deleting unattached menus

DestroyMenu(hMenuHello);

DestroyMenu(hMenuRect);

return msg.wParam;

}

162

LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

 

static HWND

hwndClient;

CLIENTCREATESTRUCT

clientcreate;

HWND

hwndChild;

MDICREATESTRUCT

mdicreate;

switch(iMsg)

{

case WM_CREATE : // Create the client window

clientcreate.hWindowMenu = hMenuInitWindow; clientcreate.idFirstChild = IDM_FIRSTCHILD;

hwndClient = CreateWindow("MDICLIENT", NULL,

WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE, 0, 0, 0, 0, hwnd,(HMENU) 1, hInst, (LPSTR) &clientcreate);

return 0;

case WM_COMMAND :

 

switch(wParam)

 

{

 

case IDM_NEWHELLO :

// Create a Hello child window

mdicreate.szClass

= szHelloClass;

mdicreate.szTitle

= "Hello";

mdicreate.hOwner

= hInst;

mdicreate.x

= CW_USEDEFAULT;

mdicreate.y

= CW_USEDEFAULT;

mdicreate.cx

= CW_USEDEFAULT;

mdicreate.cy

= CW_USEDEFAULT;

mdicreate.style

= 0;

mdicreate.lParam

= 0;

hwndChild =(HWND) SendMessage(hwndClient, WM_MDICREATE, 0, (LPARAM)(LPMDICREATESTRUCT) &mdicreate);

return 0;

 

case IDM_NEWRECT :

// Create a Rect child window

mdicreate.szClass

= szRectClass;

mdicreate.szTitle

= "Rectangles";

mdicreate.hOwner

= hInst;

mdicreate.x

= CW_USEDEFAULT;

mdicreate.y

= CW_USEDEFAULT;

mdicreate.cx

= CW_USEDEFAULT;

mdicreate.cy

= CW_USEDEFAULT;

mdicreate.style

= 0;

mdicreate.lParam

= 0;

hwndChild =(HWND) SendMessage(hwndClient, WM_MDICREATE, 0, (LPARAM)(LPMDICREATESTRUCT) &mdicreate);

return 0;

case IDM_CLOSE : // Close the active window

hwndChild =(HWND) SendMessage(hwndClient, WM_MDIGETACTIVE, 0, 0);

if(SendMessage(hwndChild, WM_QUERYENDSESSION, 0, 0)) SendMessage(hwndClient, WM_MDIDESTROY,

163

(WPARAM) hwndChild, 0);

return 0;

case IDM_EXIT :

// Exit the program

SendMessage(hwnd, WM_CLOSE, 0, 0); return 0;

// messages for arranging windows case IDM_TILE :

SendMessage(hwndClient, WM_MDITILE, 0, 0); return 0;

case IDM_CASCADE :

SendMessage(hwndClient, WM_MDICASCADE, 0, 0); return 0;

case IDM_ARRANGE :

SendMessage(hwndClient, WM_MDIICONARRANGE, 0, 0); return 0;

case IDM_CLOSEALL : // Attempt to close all children

EnumChildWindows(hwndClient, &CloseEnumProc, 0); return 0;

default : // Pass to active child...

hwndChild =(HWND) SendMessage(hwndClient, WM_MDIGETACTIVE, 0, 0);

if(IsWindow(hwndChild)) SendMessage(hwndChild, WM_COMMAND,

wParam, lParam);

break;

// ...and then to DefFrameProc

}

 

break;

 

case WM_QUERYENDSESSION :

 

case WM_CLOSE :

// Attempt to close all children

SendMessage(hwnd, WM_COMMAND, IDM_CLOSEALL, 0);

if(NULL != GetWindow(hwndClient, GW_CHILD)) return 0;

break; // I.e., call DefFrameProc

case WM_DESTROY : PostQuitMessage(0); return 0;

}

// Pass unprocessed messages to DefFrameProc(not DefWindowProc)

return DefFrameProc(hwnd, hwndClient, iMsg, wParam, lParam);

}

BOOL CALLBACK CloseEnumProc(HWND hwnd, LPARAM lParam)

{

if(GetWindow(hwnd, GW_OWNER)) // Check for icon title return 1;

SendMessage(GetParent(hwnd), WM_MDIRESTORE,(WPARAM) hwnd, 0); if(!SendMessage(hwnd, WM_QUERYENDSESSION, 0, 0))

static HWND HDC
HMENU LPHELLODATA PAINTSTRUCT RECT

164

return 1;

SendMessage(GetParent(hwnd), WM_MDIDESTROY,(WPARAM) hwnd, 0); return 1;

}

LRESULT CALLBACK HelloWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

static COLORREF clrTextArray[] = { RGB(0, 0, 0), RGB(255, 0, 0), RGB(0, 255, 0), RGB( 0, 0, 255), RGB(255, 255, 255) };

hwndClient, hwndFrame; hdc;

hMenu;

lpHelloData;

ps;

rect;

switch(iMsg)

{

case WM_CREATE :

// Allocate memory for window private data

lpHelloData =(LPHELLODATA) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HELLODATA));

lpHelloData->iColor = IDM_BLACK; lpHelloData->clrText = RGB(0, 0, 0); SetWindowLong(hwnd, 0,(long) lpHelloData);

// Save some window handles

hwndClient = GetParent(hwnd); hwndFrame = GetParent(hwndClient); return 0;

case WM_COMMAND : switch(wParam)

{

case IDM_BLACK : case IDM_RED : case IDM_GREEN : case IDM_BLUE : case IDM_WHITE :

// Change the text color

lpHelloData =(LPHELLODATA) GetWindowLong(hwnd, 0);

hMenu = GetMenu(hwndFrame); CheckMenuItem(hMenu, lpHelloData->iColor,

MF_UNCHECKED); lpHelloData->iColor = wParam; CheckMenuItem(hMenu, lpHelloData->iColor,

MF_CHECKED);

lpHelloData->clrText = clrTextArray[wParam - IDM_BLACK];

InvalidateRect(hwnd, NULL, FALSE);

}

return 0;

case WM_PAINT :

// Paint the window

165

hdc = BeginPaint(hwnd, &ps);

lpHelloData =(LPHELLODATA) GetWindowLong(hwnd, 0); SetTextColor(hdc, lpHelloData->clrText);

GetClientRect(hwnd, &rect);

DrawText(hdc, "Hello, World!", -1, &rect,

DT_SINGLELINE | DT_CENTER | DT_VCENTER);

EndPaint(hwnd, &ps); return 0;

case WM_MDIACTIVATE :

// Set the Hello menu if gaining focus

if(lParam ==(LPARAM) hwnd) SendMessage(hwndClient, WM_MDISETMENU,

(WPARAM) hMenuHello,(LPARAM) hMenuHelloWindow);

// Check or uncheck menu item

lpHelloData =(LPHELLODATA) GetWindowLong(hwnd, 0); CheckMenuItem(hMenuHello, lpHelloData->iColor,

(lParam ==(LPARAM) hwnd) ? MF_CHECKED : MF_UNCHECKED);

// Set the Init menu if losing focus

if(lParam !=(LPARAM) hwnd)

SendMessage(hwndClient, WM_MDISETMENU,(WPARAM) hMenuInit,

(LPARAM) hMenuInitWindow);

DrawMenuBar(hwndFrame); return 0;

case WM_QUERYENDSESSION : case WM_CLOSE :

if(IDOK != MessageBox(hwnd, "OK to close window?", "Hello", MB_ICONQUESTION | MB_OKCANCEL))

return 0;

break; // I.e., call DefMDIChildProc

case WM_DESTROY :

lpHelloData =(LPHELLODATA) GetWindowLong(hwnd, 0); HeapFree(GetProcessHeap(), 0, lpHelloData); return 0;

}

// Pass unprocessed message to DefMDIChildProc

return DefMDIChildProc(hwnd, iMsg, wParam, lParam);

}

LRESULT CALLBACK RectWndProc(HWND hwnd, UINT iMsg, WPARAM wParam,

LPARAM lParam)

{

 

static HWND

hwndClient, hwndFrame;

HBRUSH

hBrush;

HDC

hdc;

LPRECTDATA

lpRectData;

PAINTSTRUCT

ps;

int

xLeft, xRight, yTop, yBottom;

short

nRed, nGreen, nBlue;

166

switch(iMsg)

{

case WM_CREATE :

// Allocate memory for window private data

lpRectData =(LPRECTDATA) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RECTDATA));

SetWindowLong(hwnd, 0,(long) lpRectData);

//Start the timer going

SetTimer(hwnd, 1, 250, NULL);

//Save some window handles

hwndClient = GetParent(hwnd); hwndFrame = GetParent(hwndClient); return 0;

case WM_SIZE : // If not minimized, save the window size if(wParam != SIZE_MINIMIZED)

{

lpRectData =(LPRECTDATA) GetWindowLong(hwnd, 0);

lpRectData->cxClient = LOWORD(lParam); lpRectData->cyClient = HIWORD(lParam);

}

break;

// WM_SIZE must be processed by DefMDIChildProc

case WM_TIMER : // Display a random rectangle

lpRectData =(LPRECTDATA) GetWindowLong(hwnd, 0);

xLeft

= rand() % lpRectData->cxClient;

xRight

= rand() % lpRectData->cxClient;

yTop

= rand() % lpRectData->cyClient;

yBottom

= rand() % lpRectData->cyClient;

nRed

= rand() & 255;

nGreen

= rand() & 255;

nBlue

= rand() & 255;

hdc = GetDC(hwnd);

hBrush = CreateSolidBrush(RGB(nRed, nGreen, nBlue));

SelectObject(hdc, hBrush);

Rectangle(hdc, min(xLeft, xRight), min(yTop, yBottom), max(xLeft, xRight), max(yTop, yBottom));

ReleaseDC(hwnd, hdc); DeleteObject(hBrush); return 0;

case WM_PAINT :

// Clear the window

InvalidateRect(hwnd, NULL, TRUE); hdc = BeginPaint(hwnd, &ps); EndPaint(hwnd, &ps);

return 0;

case WM_MDIACTIVATE : // Set the appropriate menu if(lParam ==(LPARAM) hwnd)

SendMessage(hwndClient, WM_MDISETMENU,(WPARAM) hMenuRect,

167

(LPARAM) hMenuRectWindow);

else

SendMessage(hwndClient, WM_MDISETMENU,(WPARAM) hMenuInit,

(LPARAM) hMenuInitWindow);

DrawMenuBar(hwndFrame); return 0;

case WM_DESTROY :

lpRectData =(LPRECTDATA) GetWindowLong(hwnd, 0); HeapFree(GetProcessHeap(), 0, lpRectData); KillTimer(hwnd, 1);

return 0;

}

// Pass unprocessed message to DefMDIChildProc

return DefMDIChildProc(hwnd, iMsg, wParam, lParam);

}

MDIDEMO.RC

/*----------------------------

MDIDEMO.RC resource script

----------------------------*/

 

#include <windows.h>

 

#include "mdidemo.h"

 

MdiMenuInit MENU

 

{

 

POPUP "&File"

 

{

 

MENUITEM "New &Hello",

IDM_NEWHELLO

MENUITEM "New &Rectangles",

IDM_NEWRECT

MENUITEM SEPARATOR

 

MENUITEM "E&xit",

IDM_EXIT

}

 

}

 

MdiMenuHello MENU

 

{

 

POPUP "&File"

 

{

 

MENUITEM "New &Hello",

IDM_NEWHELLO

MENUITEM "New &Rectangles",

IDM_NEWRECT

MENUITEM "&Close",

IDM_CLOSE

MENUITEM SEPARATOR

 

MENUITEM "E&xit",

IDM_EXIT

}

 

POPUP "&Color"

 

{

 

MENUITEM "&Black",

IDM_BLACK

MENUITEM "&Red",

IDM_RED

MENUITEM "&Green",

IDM_GREEN

MENUITEM "B&lue",

IDM_BLUE

MENUITEM "&White",

IDM_WHITE

}

 

POPUP "&Window"

 

{

 

MENUITEM "&Cascade\tShift+F5",

IDM_CASCADE

MENUITEM "&Tile\tShift+F4",

IDM_TILE

MENUITEM "Arrange &Icons",

IDM_ARRANGE

MENUITEM "Close &All",

IDM_CLOSEALL

}

 

}

 

MdiMenuRect MENU

168

{

 

 

POPUP "&File"

 

 

{

 

 

MENUITEM "New &Hello",

IDM_NEWHELLO

MENUITEM "New &Rectangles",

IDM_NEWRECT

MENUITEM "&Close",

IDM_CLOSE

MENUITEM SEPARATOR

 

MENUITEM "E&xit",

IDM_EXIT

}

 

 

POPUP "&Window"

 

 

{

 

 

MENUITEM "&Cascade\tShift+F5",

IDM_CASCADE

MENUITEM "&Tile\tShift+F4",

IDM_TILE

MENUITEM "Arrange &Icons",

IDM_ARRANGE

MENUITEM "Close &All",

IDM_CLOSEALL

}

 

 

}

 

 

MdiAccel ACCELERATORS

 

 

{

 

 

VK_F5, IDM_CASCADE, VIRTKEY, SHIFT

 

VK_F4, IDM_TILE,

VIRTKEY, SHIFT

 

}

 

 

MDIDEMO.H

 

 

/*-----------------------

 

 

MDIDEMO.H header file

 

 

-----------------------

*/

 

#define EXPORT

__declspec(dllexport)

#define INIT_MENU_POS

0

 

#define HELLO_MENU_POS

2

 

#define RECT_MENU_POS

1

 

#define IDM_NEWHELLO

10

 

#define IDM_NEWRECT

11

 

#define IDM_CLOSE

12

 

#define IDM_EXIT

13

 

#define IDM_BLACK

20

 

#define IDM_RED

21

 

#define IDM_GREEN

22

 

#define IDM_BLUE

23

 

#define IDM_WHITE

24

 

#define IDM_TILE

30

 

#define IDM_CASCADE

31

 

#define IDM_ARRANGE

32

 

#define IDM_CLOSEALL

33

 

#define IDM_FIRSTCHILD 100

Рис. 18.2 Текст программы MDIDEMO

Программа MDIDEMO поддерживает два типа предельно простых окон документов: в одном в центре рабочей области выводится фраза "Hello, World!", а во втором отображается последовательность случайных прямоугольников. (В листингах исходных текстов программы и именах идентификаторов они упоминаются как документ Hello и документ Rect.) С каждым из этих двух типов окон документов связано свое меню. Окно документа, в котором выводятся слова "Hello, World!", имеется меню, дающее возможность изменять цвет символов.

Соседние файлы в предмете Операционные системы