底层的MDI程序是如何建立的

572人阅读 评论(0) 收藏 举报
分类:

代码示例:

// MDIAppDemo.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "MDIAppDemo.h"

#define ID_FIRSTWINDOW 50000

typedef struct tagHELLODATA
{
	UINT	 iColorIndex;
	COLORREF clrText;
} HELLODATA, *PHELLODATA;

typedef struct tagRECTDATA
{
	short cxClient;
	short cyClient;
}RECTDATA, *PRECTDATA;

// 前置函数申明
LRESULT CALLBACK	FrameWndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK	HelloWndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK	RectWndProc(HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK CloseEnumProc(HWND, LPARAM);

//全局变量
TCHAR szFrameWndClass[] = _T("FrameWndClass");
TCHAR szHelloWndClass[] = _T("HelloWndClass");
TCHAR szRectWndClass[] = _T("RectWndClass");

HMENU hMenuInit;
HMENU hMenuInitWindow;
HMENU hMenuHello;
HMENU hMenuHelloWindow;
HMENU hMenuRect;
HMENU hMenuRectWindow;

HINSTANCE hInst;

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

	hInst = hInstance;

	WNDCLASS wc;

	//注册主框架类
	wc.style			= CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc		= FrameWndProc;
	wc.cbClsExtra		= 0;
	wc.cbWndExtra		= sizeof(HANDLE);
	wc.hInstance		= hInstance;
	wc.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MDIAPPDEMO));
	wc.hCursor			= LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground	= (HBRUSH)(COLOR_APPWORKSPACE+1);
	wc.lpszMenuName		= NULL;
	wc.lpszClassName	= szFrameWndClass;

	RegisterClass(&wc);

	//注册Hello窗口类
	wc.style			= CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc		= HelloWndProc;
	wc.cbClsExtra		= 0;
	wc.cbWndExtra		= 0;
	wc.hInstance		= hInstance;
	wc.hIcon			= LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor			= LoadCursor(NULL, IDC_IBEAM);
	wc.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName		= NULL;
	wc.lpszClassName	= szHelloWndClass;

	RegisterClass(&wc);

	//注册Rect窗口类
	wc.style			= CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc		= RectWndProc;
	wc.cbClsExtra		= 0;
	wc.cbWndExtra		= sizeof(HANDLE);
	wc.hInstance		= hInstance;
	wc.hIcon			= LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor			= LoadCursor(NULL, IDC_CROSS);
	wc.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName		= NULL;
	wc.lpszClassName	= szRectWndClass;

	RegisterClass(&wc);

	//初始化菜单
	hMenuInit = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_INIT));
	hMenuInitWindow = GetSubMenu(hMenuInit, 0);

	hMenuHello = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_HELLO));
	hMenuHelloWindow = GetSubMenu(hMenuHello, 2);

	hMenuRect = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_RECT));
	hMenuRectWindow = GetSubMenu(hMenuRect, 1);

	HWND hWndFrame = CreateWindow(szFrameWndClass,
								  _T("MDIAppDemo"),
								  WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
								  CW_USEDEFAULT,
								  CW_USEDEFAULT,
								  CW_USEDEFAULT,
								  CW_USEDEFAULT,
								  NULL,
								  hMenuInit,
								  hInstance,
								  NULL);
	HWND hWndClient = GetWindow(hWndFrame, GW_CHILD);

	ShowWindow(hWndFrame, nCmdShow);
	UpdateWindow(hWndFrame);

	// 主消息循坏
	MSG msg;
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
		
	}

	//清理工作
	DestroyMenu(hMenuHello);
	DestroyMenu(hMenuRect);

	return (int) msg.wParam;
}

LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	static HWND hwndClient;
	CLIENTCREATESTRUCT clientCreateStruct;

	HWND hwndChild;
	MDICREATESTRUCT mdiCreateStruct;
	
	
	switch(uMsg)
	{
	case WM_CREATE:
		clientCreateStruct.hWindowMenu = hMenuInitWindow;
		clientCreateStruct.idFirstChild = ID_FIRSTWINDOW;
		hwndClient = CreateWindow(_T("MDIClient"),
								  NULL,
								  WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE,
								  0,0,0,0,									//注意:这里都是0!
								  hwnd,
								  (HMENU)1,
								  hInst,
								  (PSTR)(&clientCreateStruct));

		return 0;

	case WM_COMMAND:
		switch(LOWORD(wParam))
		{
		case IDM_FILE_NEWHELLO:
			mdiCreateStruct.szClass = szHelloWndClass;
			mdiCreateStruct.szTitle = _T("Hello Window");
			mdiCreateStruct.hOwner = hInst;
			mdiCreateStruct.x = CW_USEDEFAULT;
			mdiCreateStruct.y = CW_USEDEFAULT;
			mdiCreateStruct.cx = CW_USEDEFAULT;
			mdiCreateStruct.cy = CW_USEDEFAULT;
			mdiCreateStruct.style = 0;
			mdiCreateStruct.lParam = 0;

			hwndChild = (HWND)SendMessage(hwndClient, WM_MDICREATE, 0, (LPARAM)(LPMDICREATESTRUCT)&mdiCreateStruct);
			return 0;
		
		case IDM_FILE_NEWRECT:
			mdiCreateStruct.szClass = szRectWndClass;
			mdiCreateStruct.szTitle = _T("Rect Window");
			mdiCreateStruct.hOwner = hInst;
			mdiCreateStruct.x = CW_USEDEFAULT;
			mdiCreateStruct.y = CW_USEDEFAULT;
			mdiCreateStruct.cx = CW_USEDEFAULT;
			mdiCreateStruct.cy = CW_USEDEFAULT;
			mdiCreateStruct.style = 0;
			mdiCreateStruct.lParam = 0;

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

		case IDM_FILE_CLOSE:
			hwndChild = (HWND)SendMessage(hwndClient, WM_MDIGETACTIVE, 0, 0);
			if(SendMessage(hwndChild, WM_QUERYENDSESSION, 0, 0))
				SendMessage(hwndClient, WM_MDIDESTROY, (WPARAM)hwndChild, 0);

			return 0;

		case IDM_FILE_EXIT:
			SendMessage(hwnd, WM_CLOSE, 0, 0);
			return 0;
		
		//窗口布局
		case IDM_WINDOW_TILE:
			SendMessage(hwndClient, WM_MDITILE, 0, 0);
			return 0;

		case IDM_WINDOW_CASCADE:
			SendMessage(hwndClient, WM_MDICASCADE, 0, 0);
			return 0;

		case IDM_WINDOW_ARRANGEICONS:
			SendMessage(hwndClient, WM_MDIICONARRANGE, 0, 0);
			return 0;

		case IDM_WINDOW_CLOSEALL:
			EnumChildWindows(hwndClient, CloseEnumProc, 0);

			return 0;

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

			if(IsWindow(hwndChild))
			{
				SendMessage(hwndChild, WM_COMMAND, wParam, lParam);
			}
			break;
		}// end inner switch
		
		break;

	case WM_QUERYENDSESSION:
	case WM_CLOSE:
		SendMessage(hwnd, WM_COMMAND, IDM_WINDOW_CLOSEALL, 0);
		
		//尝试关闭所有窗口
		if(NULL != GetWindow(hwndClient, GW_CHILD))
		{
			//如果这个if语句体执行了,说明还有子窗口没有被关闭
			return 0;
		}

		break;

	case WM_DESTROY:
		PostQuitMessage(0);
	
	}// end outer switch

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

}

LRESULT CALLBACK HelloWndProc(HWND hwnd, UINT uMsg, 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)
									};
	static HWND hwndClient, hwndFrame;
	HMENU hFrameMenu;
	PHELLODATA pHelloData;
	HDC hdc;
	PAINTSTRUCT ps;
	RECT rect;
	switch(uMsg)
	{
	case WM_CREATE:
		pHelloData = (PHELLODATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HELLODATA));
		pHelloData->iColorIndex = IDM_COLOR_BLACK;
		pHelloData->clrText = clrTextArray[0];
		SetWindowLong(hwnd, GWL_USERDATA, (long)pHelloData);

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

		return 0;

	case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);
		pHelloData = (PHELLODATA)GetWindowLong(hwnd, GWL_USERDATA);
		SetTextColor(hdc, pHelloData->clrText);
		GetClientRect(hwnd, &rect);
		DrawText(hdc, _T("Hello World!"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
		EndPaint(hwnd, &ps);

	case WM_COMMAND:
		switch(LOWORD(wParam))
		{
		//从IDM_COLOR_BLACK至IDM_COLOR_WHITE,其ID数值必须是连续的
		case IDM_COLOR_BLACK:
		case IDM_COLOR_RED:
		case IDM_COLOR_GREEN:
		case IDM_COLOR_BLUE:
		case IDM_COLOR_WHITE:
			pHelloData = (PHELLODATA)GetWindowLong(hwnd, GWL_USERDATA);
			hFrameMenu = GetMenu(hwndFrame);
			CheckMenuItem(hFrameMenu, pHelloData->iColorIndex, MF_UNCHECKED);
			//对于菜单的WM_COMMAND消息,wParam高位为0,低位为菜单的ID
			//所以此时wParam等于LOWORD(wParam)
			pHelloData->iColorIndex = wParam;
			CheckMenuItem(hFrameMenu, pHelloData->iColorIndex, MF_CHECKED);
			pHelloData->clrText = clrTextArray[wParam - IDM_COLOR_BLACK];

			InvalidateRect(hwnd, NULL, FALSE);
		}
	return 0;

	//注意与WM_MDIGETACTIVE区分
	case WM_MDIACTIVATE:
		if(lParam == (LPARAM)hwnd)
			SendMessage(hwndClient, WM_MDISETMENU, (WPARAM)hMenuHello, (LPARAM)hMenuHelloWindow);

		pHelloData = (PHELLODATA)GetWindowLong(hwnd, GWL_USERDATA);
		CheckMenuItem(hMenuHello, pHelloData->iColorIndex, (lParam == (LPARAM)hwnd) ? MF_CHECKED : MF_UNCHECKED);

		//如果当前窗口失去焦点,则将菜单还原成初始菜单
		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,_T("OK to close window?"), _T("Hello"), MB_ICONQUESTION | MB_OKCANCEL))
			return 0;

		break;

	case WM_DESTROY:
		pHelloData = (PHELLODATA)GetWindowLong(hwnd, 0);
		HeapFree(GetProcessHeap(), 0, pHelloData);
		return 0;
	
	}

	return DefMDIChildProc(hwnd, uMsg, wParam, lParam);
}


BOOL CALLBACK CloseEnumProc(HWND hwnd, LPARAM lParam)
{
	if(GetWindow(hwnd, GW_OWNER))
		return TRUE;

	SendMessage(GetParent(hwnd), WM_MDIRESTORE, (WPARAM)hwnd, 0);

	if(!SendMessage(hwnd, WM_QUERYENDSESSION, 0, 0))
		return TRUE;

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

	return TRUE;
}


LRESULT CALLBACK RectWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	static HWND hwndClient, hwndFrame;
	PRECTDATA pRectData;
	int iLeft, iRight, iTop, iBottom;
	short nRed, nGreen, nBlue;
	HDC hdc;
	PAINTSTRUCT ps;
	HBRUSH hBrush;
	
	switch(uMsg)
	{
	case WM_CREATE:
		pRectData = (PRECTDATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RECTDATA));
		SetWindowLong(hwnd, 0, (long)pRectData);

		
		SetTimer(hwnd, 1, 250, NULL);
		
		hwndClient = GetParent(hwnd);
		hwndFrame = GetParent(hwndClient);

		return 0;
	
	case WM_SIZE:
		if(wParam != SIZE_MINIMIZED)
		{
			pRectData = (PRECTDATA)GetWindowLong(hwnd, 0);
			pRectData->cxClient = LOWORD(lParam);
			pRectData->cyClient = HIWORD(lParam);
		}

		break;

	case WM_TIMER:
		pRectData = (PRECTDATA)GetWindowLong(hwnd, 0);
		iLeft = rand() % pRectData->cxClient;
		iRight = rand() % pRectData->cxClient;;
		iTop = rand() % pRectData->cyClient;
		iBottom = rand() % pRectData->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(iLeft, iRight), min(iTop, iBottom), max(iLeft, iRight), max(iTop, iBottom));

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

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

		return 0;

	case WM_MDIACTIVATE:
		if(lParam == (LPARAM)hwnd)
			SendMessage(hwndClient, WM_MDISETMENU, (WPARAM)hMenuRect, (LPARAM)hMenuRectWindow);
		else
			SendMessage(hwndClient, WM_MDISETMENU, (WPARAM)hMenuInit, (LPARAM)hMenuInitWindow);

		DrawMenuBar(hwndFrame);
		return 0;

	case WM_DESTROY:
		pRectData = (PRECTDATA)GetWindowLong(hwnd, 0);
		HeapFree(GetProcessHeap(), 0, pRectData);
		KillTimer(hwnd, 1);

		//因为子窗口的创建与子窗口本身无关,而是由Client窗口创建的,所以不需要发送PostQuitMessage()
		return 0;
	}

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

}


查看评论

主窗体为MDI,子窗体的建立写到了DLL里,代码见内,如何判断使子窗体只CREATE一次?

建1个StringList;procedure ShowChild(form:TForm);StdCall;var  ptr:PLongint;  Form1:TForm1;begin  if Str...
  • liufuyahong
  • liufuyahong
  • 2005年07月09日 17:34
  • 970

什么是MDI窗体?

转自: 接触MDI窗体已经很久了,用了也非常多,如今在一些用户体验好的软件上,也多采用MDI窗体技术,如我们现在常用的遨游浏览器,还有Word、Excel等。 但是什么是MDI窗体呢?...
  • wljhk2006
  • wljhk2006
  • 2014年04月24日 16:04
  • 547

delphi的DLL封装MDI子窗体

转自http://www.cnblogs.com/kfarvid/archive/2010/06/23/1763753.html 前天遇到一个疑问:主窗体是fsMDIForm时,调用DLL的窗体不可...
  • aTian2009
  • aTian2009
  • 2012年04月23日 09:31
  • 2625

子窗体创建过程

在主窗体FORM1 implementation 加入 uses unit2   在主窗体中按钮创建子窗体:  if not assigned(form2) then  //判定子窗体是否存在  fo...
  • beyond911
  • beyond911
  • 2009年07月15日 21:18
  • 163

一个简单的MDI示范程序(Delphi)

本文转自 http://www.cnblogs.com/ywangzi/archive/2012/07/13/2588979.html
  • hksoobe
  • hksoobe
  • 2014年08月06日 00:19
  • 286

Delphi MDI 子窗体的创建和销毁 [zhuan]

文章来源: Delphi MDI 子窗体的创建和销毁 1.如果要创建一个mdi child,先看是否有这个child 存在,如果有,则用它,如果没有再创建 //该函数判断MDI 子窗体是否存在,再...
  • shao882
  • shao882
  • 2015年01月22日 22:00
  • 482

Windows应用程序C#创建MDI父窗体和子窗体

一:创建父窗体1.创建 Windows 应用程序.2.在"属性"窗口中,将 IsMDIContainer 属性设置为true. 这将该窗体指定为子窗口的MDI 容器.3.设置菜单栏工具栏等控件.假设点...
  • ruguo_58
  • ruguo_58
  • 2007年11月25日 20:58
  • 2254

mdi窗口加背景图片

forwardglobal type w_abc from windowend typetype mdi_1 from mdiclient within w_abcend typetype p_1 f...
  • MakeToday
  • MakeToday
  • 2006年11月18日 14:56
  • 1620

Winform MDI

VS2012创建Winform MDI 程序的步骤
  • u013688451
  • u013688451
  • 2016年10月17日 16:52
  • 566

PB中MDI说明和使用

〖MDI〗-Multiple Document Interface *菜单是MDI应用中必不可少的,不仅Frame必须有一个菜单,就连在客户区打开的各个Sheet也应该有菜单,如果没有就会自动继承前...
  • u012369435
  • u012369435
  • 2014年07月02日 17:36
  • 1289
    个人资料
    专栏达人 持之以恒
    等级:
    访问量: 23万+
    积分: 3816
    排名: 1万+
    欢迎关注『高性能服务器开发』公众号
    欢迎关注『高性能服务器开发』公众号
    博客专栏
    最新评论