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

代码示例:

// 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);

}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Winform MDI是指使用Windows窗体应用程序中的多文档界面(Multiple Document Interface, MDI)功能。MDI允许在一个父窗体中打开多个子窗体,以在一个应用程序中同时处理多个文档或任务。MDI窗体的设置非常简单,只需要将窗体的属性IsMdiContainer设置为True即可。 要在MDI中打开子窗体,需要先创建子窗体对象,并将子窗体的MdiParent属性设置为父窗体,然后调用子窗体的Show方法显示子窗体。例如,可以使用以下代码在MDI中打开Form1窗体: Form1 f3 = new Form1(); f3.MdiParent = this; f3.Show(); 在MDI中,还可以使用MdiLayout枚举值来定义子窗体的布局。具体包括Cascade层叠排列子窗体、TileHorizontal水平平铺子窗体和TileVertical垂直平铺子窗体。这些布局可以根据用户的需求来选择适合的方式来排列子窗体。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [WinForm——MDI窗体](https://blog.csdn.net/hhhhhhhhhhwwwwwwwwww/article/details/105633316)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [C#winform 之MDI容器](https://blog.csdn.net/qq_57798018/article/details/128232962)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值