Win32子窗口及其創建應用

簡介:
所謂的子窗口就是一個父窗口裏的一個窗口,父窗口也叫主窗口。子窗口也是窗口,它有自己的回調函數、自己的窗口類、自己的創建。它位於主窗口裏的一個區域,我們可以設置子窗口的大小和位置以及相關屬性。子窗口與主窗口之間是相聯繫的,它們通過句柄和消息等訪問彼此的。

特別提醒:
後面所講的子窗口控件是一種特殊的子窗口。子窗口控件不需要我們來定義窗口類,系統已經幫我們定義好了,我們自己引用就好。

這裏我們先介紹普通子窗口。


一、子窗口的創建

創建過程:
1.註冊窗口類(我們在主窗口註冊後面接着註冊子窗口)
2.創建子窗口(一般在WS_CREATE消息處理中創建,和創建主窗口一樣使用CreateWindow函數,參數不同哦,需加上WS_CHILD和WS_VISIBLE風格)
3.定義子窗口的回調函數(子窗口回調函數和主窗口回調函數大致一樣,改下函數名)

1.註冊窗口類

子窗口類參數基本和主窗口一樣,一般只需修改一下四個參數即可。

// 註冊主窗口後面,修改四個參數
wc.cbClsExtra = sizeof(long);    // 預留空間
wc.hIcon = NULL;                 // 圖標設爲空
wc.lpfnWndProc = ChildWndProc;   // 回調函數
wc.lpszClassName = TEXT("ChildWindow");   // 子窗口類名

// 註冊子窗口類
RegisterClassEx(&wc);

2.創建子窗口

CreateWindow參數的比較:

參數 主窗口 子窗口
窗口類名 自己定義 自己定義
窗口標題 自己定義 NULL
窗口樣式 WS_OVERLAPPEDWINDOW WS_CHILDWINDOWWS_VISIBLE
水平位置 CW_USEDEFAULT 0(後面可通過MoveWindow函數修改)
垂直位置 CW_USEDEFAULT 0(後面可通過MoveWindow函數修改)
寬度 CW_USEDEFAULT 0(後面可通過MoveWindow函數修改)
高度 CW_USEDEFAULT 0(後面可通過MoveWindow函數修改)
父窗口句柄 NULL hwnd
菜單句柄/子ID NULL (HMENU) (y << 8 |x) 不同子ID就行
實體句柄 hInstance (HINSTANCE)GetWindowLong (hwnd, GWL_HINSTANCE)(LPCREATESTRUCT)lParam->hInstance
額外參數lParam NULL NULL

子窗口是否顯示可調用ShowWindow函數進行修改,窗口的大小、位置可以通過MoveWindow函數進行修改。

// 創建25個子窗口
case WM_CREATE:
{
	for (i = 0; i < 5; i++)
	{
		for (j = 0; j < 5; j++)
		{
		 childhwnd[i][j]=CreateWindow(TEXT("ChildWindow"), NULL, 
				           WS_CHILD|WS_VISIBLE,
							0, 0, 0 ,0, 
							hwnd, (HMENU)(x++),
						 (HINSTANCE)GetWindowLong (hwnd, GWL_HINSTANCE), NULL);
		}
	}
break;
}

3.定義子窗口回調函數

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam);  // 主窗口回調函數
LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam);  // 子窗口回調函數

LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
	switch(Message)
	{
	case WM_LBUTTONDOWN:
	{
		ShowWindow(hwnd, SW_HIDE);
		break;
	}
	default:
		return DefWindowProc(hwnd, Message, wParam, lParam);   //讓系統處理消息,這條語句一定要加上
	}
	return 0;
}

二、子窗口與主窗口的聯繫

1.主窗口訪問子窗口(發送消息)

GetWindowLongPrt函數:獲取窗口信息

LONG_PTR GetWindowLongPtr(HWND hWnd,   // 窗口句柄
                          int nIndex);   // 獲取的信息指定值
參數 含義
GWL_EXSTYLE 獲取擴展窗口樣式。更多信息,查閱CreateWindowEx.
GWL_STYLE 獲取窗口樣式(window styles)
GWLP_WNDPROC 獲取窗口程序指示器,或描述指示器的句柄 。如果使用此參數,必須使用CallWindowProc回調函數。
GWLP_HINSTANCE 獲取一個應用程序實例的句柄 。
GWLP_HWNDPARENT 如果只有一個父窗口,獲取父窗口的句柄 。
GWLP_ID 獲取窗口標識符。
GWLP_USERDATA 獲取窗口關聯的數據,是應用程序創建窗口時留給用戶的數據。初始值是0。
DWLP_DLGPROC 獲取一個對話框的指示器,或描述指示器的句柄 。如果使用此參數,必須使用CallWindowProc回調函數。
DWLP_MSGRESULT 獲取一個對話框中的被處理的信息的值。
DWLP_USER 作爲指示器或句柄來獲取私有應用程序的額外的信息。

GetDlgCtrlID函數:獲取指定控件的ID號
ID是針對子窗體而言的,窗體時把這個ID號傳遞給hMenu參數。

int GetDlgCtrlID(HWND hwndCtl);  // 子窗口句柄

GetDlgItem函數:獲取指定ID的句柄

HWND childhwnd = GetDlgItem(Parenthwnd,ID);

MoveWindow函數:改變指定窗口的位置和大小
對基窗口來說,位置和大小取決於屏幕的左上角;對子窗口來說,位置和大小取決於父窗口客戶區的左上角.對於Owned窗口,位置和大小取決於屏幕左上角.

BOOL MoveWindow( HWND hWnd, int X, int Y, int nWidth, int nHeight, 
                 BOOL bRepaint );   // TRUE重畫,FALSE不重畫

SendMessage函數:將指定的消息發送到一個或多個窗口
SendMessage函數爲指定的窗口調用窗口程序,直到窗口程序處理完消息再返回。
PostMessage函數是將一個消息寄送到一個線程的消息隊列後就立即返回。

LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam)

2.子窗口訪問主窗口(發送消息)

  • 獲得一個指定子窗口的父窗口句柄:GetParent
  • 將指定的消息發送到一個或多個窗口:SendMessage
HWND GetParent(HWND hWnd);

三、子窗口的應用:翻牌

簡介:
這裏創建了25個子窗口,開始設置25個子窗口都可見,後面主窗口和子窗口分別相應鼠標左鍵按下的消息,主窗口收到消息顯示子窗口,子窗口收到消息隱藏子窗口,ShowWindow可以實現。子窗口顯示時就看不到圖片,子窗口不顯示能看到圖片。子窗口隱藏狀態時,子窗口就消失了,不能接受鼠標按下消息了。這裏需要注意的是,當我們點擊子窗口時,主窗口是收不到按鍵消息的,子窗口通過自己的回調函數處理消息。
在這裏插入圖片描述

在這裏插入圖片描述

在這裏插入圖片描述
代碼如下:有註釋的

#include <windows.h>
#include"strsafe.h"    // 安全字符串操作
// 定義回調函數
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam);

HINSTANCE hInst;   // 用來保存實例句柄,在下面創建子窗口CreateWindow用到
#define NUM 5    // 宏定義

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
	WNDCLASSEX wc;
	HWND hwnd;
	MSG msg;

//  註冊主窗口類
	memset(&wc, 0, sizeof(wc));
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.lpfnWndProc = WndProc;
	wc.hInstance = hInstance;
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wc.lpszClassName = TEXT("WindowClass");
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

	if (!RegisterClassEx(&wc)) {
		MessageBox(NULL, TEXT("Window Registration Failed!"), TEXT("Error!"), MB_ICONEXCLAMATION | MB_OK);
		return 0;
	}
 
 // 註冊子窗口類
	wc.cbClsExtra = sizeof(long);
	wc.hIcon = NULL;
	wc.lpfnWndProc = ChildWndProc;
	wc.lpszClassName = TEXT("ChildWindow");
	RegisterClassEx(&wc);

// 創建主窗口
	hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("WindowClass"), TEXT("Caption"), WS_CAPTION|WS_SYSMENU,
		CW_USEDEFAULT, /* x */
		CW_USEDEFAULT, /* y */
		520, /* width */
		542, /* height */
		NULL, NULL, hInstance, NULL);

	hInst = hInstance;   // 保存實例句柄

	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);

	if (hwnd == NULL) {
		MessageBox(NULL, TEXT("Window Creation Failed!"), TEXT("Error!"), MB_ICONEXCLAMATION | MB_OK);
		return 0;
	}
	while (GetMessage(&msg, NULL, 0, 0) > 0) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}

// 主函數回調函數
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT ps;
	HDC hdc,mdc;
	static int cxClient, cyClient,x=0,cx,cy;
	static HWND childhwnd[NUM][NUM];
	HBITMAP bmp;
	int i, j;
	WCHAR str[100];

	switch (Message)
	{

// 創建25個子窗口
	case WM_CREATE:
	{
		for (i = 0; i < NUM; i++)
		{
			for (j = 0; j < NUM; j++)
			{
				childhwnd[i][j]=CreateWindowEx(0,TEXT("ChildWindow"), NULL, WS_CHILD|WS_VISIBLE,
							100*i, /* x */
							100*j, /* y */
							98, /* width */
							98, /* height */
							hwnd, (HMENU)(x++), hInst, NULL);
			}
		}
		break;
	}
	
	// 將趙麗穎美圖貼上去,前面博客有講
	case WM_PAINT:
	{
		hdc = BeginPaint(hwnd, &ps);
		mdc = CreateCompatibleDC(hdc);
		bmp = (HBITMAP)LoadImage(hInst, MAKEINTRESOURCEW(101), IMAGE_BITMAP, 500, 500, LR_CREATEDIBSECTION);
		SelectObject(mdc, bmp);
		BitBlt(hdc, 0, 0, 500, 500, mdc, 0, 0, SRCCOPY);
		EndPaint(hwnd, &ps);
		break;
	}

   // 主窗口響應左鍵,顯示子窗口
	case WM_LBUTTONDOWN:
	{
		cx = LOWORD(lParam);
		cy = HIWORD(lParam);
		i = cx/100;
		j =  cy/100;
		ShowWindow(childhwnd[i][j], SW_SHOW);  // 顯示子窗口
	
		break;
	}
	case WM_DESTROY:
	{
		PostQuitMessage(0);
		break;
	}

	default:
		return DefWindowProc(hwnd, Message, wParam, lParam);
	}

	return 0;
}

// 子窗口回調函數
LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
	switch(Message)
	{
	// 子窗口響應左鍵,隱藏子窗口
	case WM_LBUTTONDOWN:
	{
		ShowWindow(hwnd, SW_HIDE);
		break;
	}
	
	// 其他消息處理,不能忘記啊
	default:
		return DefWindowProc(hwnd, Message, wParam, lParam);
	}
	return 0;
}

作者說:
這世道真的是人善被人欺!你越不反抗,別人越沒有什麼畏懼,就喜歡來惹事欺負,她總以爲自己有多麼了不起。媽的,你們一家子是看着我媽好欺負是吧,有事沒事就對我媽發脾氣罵人,我媽這纔上去幾天,都到我媽住的地方故意來找事了,罵的話還那麼難聽,真的,要是我不在,不然我真想衝上去,我媽本來就身體不好,不能着急的,心疼我媽。這人真的是,自己人品有問題還說我媽,要是你人好,怎麼會和自己婆婆一見面就吵架,都呆在孃家二十幾年了吧,你有本事咋不回去,在廠裏幹個活,三天兩天不是和這個吵就是和那個吵,和我媽還是孃家的表姐妹,有這樣做姐妹的呀,我是天底下沒見過,既然你們一家子也說了,親戚能走就走,不能走就不走,我也覺得這樣最好,我以後也不希望能沾你們的光,大路朝天各走一邊。別人罵我媽心裏不好受,在這裏吐槽一下,希望大家理解。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章