SDK 控件

目录

控件

控件创建

控件的消息处理

总代码


本篇文章对控件的学习,只是对基础的部分,简单的使用,包括消息的处理上,并不涉及深入的内容。

控件

区分控件,资源:

SDK通常提供了一系列常用的用户界面控件,如按钮、文本框、列表框、组合框等。开发人员可以使用这些控件来构建应用程序的用户界面。SDK通常提供了各种图像、图标和光标资源,开发人员可以使用这些资源来美化应用程序的用户界面。

控件的使用很方便,直接拖过去即可

SDK 控件_第1张图片

程序员只需要处理好这些控件的消息也就是(ID)即可

所有控件消息都是WM_COMMAND,各种不同消息的区分就要靠 wParam,lParam这两个参数的信息

一些常用控件的学习可以参考:SDK05- 控件_黑桃鱼的博客-CSDN博客

他人珠玉在前,不再献丑

控件创建

创建控件其实也就是创建一个窗口,指定一个父窗口即可,同时安排好控件的大小位置

按钮一

	// 创建子窗口(控件)控件的操作都会产生Command消息
	HWND hButton1 = CreateWindowEx(0,
		_T("BUTTON"),
		_T("是否打勾"),
		WS_CHILD | WS_VISIBLE | BS_CHECKBOX | LBS_NOTIFY,  //组合属性,可拉伸窗口
		0,
		0,
		100,
		50,
		hWnd,
		(HMENU)IDB_BUTTON1,
		g_hInstance,
		NULL);

按钮二

	HWND hButton2 = CreateWindowEx(0,
		_T("BUTTON"),
		_T("粘贴"),
		WS_CHILD | WS_VISIBLE, // 还可以给按加别的样式BS_开头
		100,                    //按钮可打勾
		0,
		100,
		50,
		hWnd,
		(HMENU)IDB_BUTTON2,
		g_hInstance,
		NULL);

编辑框

	HWND hEdit = CreateWindowEx(0,
		_T("Edit"),
		NULL,
		WS_CHILD | WS_VISIBLE | WS_VSCROLL |
		ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL,  //组合属性,可拉伸窗口
		0,     // ws通用 es Edit控件单独有的
		60,
		200,
		100,
		hWnd,
		(HMENU)IDE_Edit1,
		g_hInstance,
		NULL);

列表

	HWND hListBox = CreateWindowEx(0,
		_T("ListBox"),
		_T("编程语言列表"),
		WS_CHILD | WS_VISIBLE | WS_VSCROLL | LBS_HASSTRINGS,  //组合属性,可拉伸窗口
		0,     // ws通用 es Edit控件单独有的
		200,
		200,
		100,
		hWnd,
		(HMENU)IDL_LISTBOX,
		g_hInstance,
		NULL);

控件的消息处理

控件的消息都会被转换成WM_COMMAND消息

SDK 控件_第2张图片

代码如下:

lParam是控件的句柄,在逻辑中就是先判断是控件的消息,控件句柄是否为空,是控件的消息的话,再更具wParam的低字(控件标识符)来进一步区分是哪一个控件,wParam的高字则是消息,再去进一步处理

LRESULT OnCommand(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	OutputDebugString(_T("[51asm] OnCommand\n"));
	WORD wID = LOWORD(wParam);
	WORD wNotifyCode = HIWORD(wParam);
	HWND hColtrol = (HWND)lParam;
	if (hColtrol != NULL) { //控件
		if (wID == IDB_BUTTON1) {
			if (wNotifyCode == BN_CLICKED) {
				LRESULT Result = SendMessage(hColtrol, BM_GETCHECK, 0, 0);
				if (BST_CHECKED == Result) {
					SendMessage(hColtrol, BM_SETCHECK, BST_UNCHECKED, NULL);
					MessageBox(NULL, _T("未婚"), _T("婚姻状况"), MB_OK);
				}
				else if (BST_UNCHECKED == Result) {
					SendMessage(hColtrol, BM_SETCHECK, BST_CHECKED, NULL);
					MessageBox(NULL, _T("已婚"), _T("婚姻状况"), MB_OK);
				}
			}
		}
		else if (wID == IDB_BUTTON2) {
			if (wNotifyCode == BN_CLICKED) {
				HWND hEdit = GetDlgItem(hwnd, IDE_Edit1);
				char szText[] = { "" };
				SendMessage(hEdit, WM_SETTEXT, 0, (LPARAM)szText); // 直接调用窗口过程函数,知道过程函数返回,否则就会一直卡在这里
				SendMessage(hEdit, WM_PASTE, 0, 0);
			}
		}
		
		if (wID == IDL_LISTBOX && wNotifyCode == LBN_SELCHANGE) {
			int nIndex = SendMessage(hColtrol, LB_GETCURSEL, 0, 0);
			if (nIndex != -1) {
				int nLen = SendMessage(hColtrol, LB_GETTEXTLEN, nIndex, 0);
				LPVOID lpBuff = malloc(nLen+1);
				SendMessage(hColtrol, LB_GETTEXT, nIndex, (LPARAM)lpBuff);
				MessageBoxA(hwnd, (char*)lpBuff, "51asm", MB_OK);
				free(lpBuff);
			}
		}
		return TRUE;
	}

	switch (wID) {
	case IDM_OPEN:
		MessageBox(NULL, _T("打开"), _T("51asm"), MB_OK);
		break;
	case IDM_SAVE:
		MessageBox(NULL, _T("保存"), _T("51asm"), MB_OK);
	case IDM_EXIT:
		SendMessage(hwnd, WM_USER + 1, NULL, NULL);// 向窗口发送一个消息
		PostQuitMessage(0); // 给自己投递QUIT消息
		// 操作窗口,想窗口发消息  WM_USER 0x0400开始
		//SendMessage(hwnd,WM_USER+1,NULL,NULL);// 向窗口发送一个消息
		break;
	}
	
	return TRUE;
}

总代码

#include 
#include 
#include 
#include 

#ifdef _DEBUG
	#define MYOUTPUT OutputDebugString
#else 
	#define MYOUTPUT
#endif // DEBUG



#define IDM_OPEN 102
#define IDM_SAVE 103
#define IDM_EXIT 104

#define IDB_BUTTON1 105
#define IDB_BUTTON2 106
#define IDE_Edit1 107
#define IDL_LISTBOX 108

#define MY_MSG WM_USER+1  // 用户自定义消息

using namespace std;

string g_Text;
TEXTMETRIC g_tm; // 字体信息

HINSTANCE g_hInstance = NULL;


void ShowErrorMsg() {
	LPVOID lpMsgBuf;
	FormatMessage(
		FORMAT_MESSAGE_ALLOCATE_BUFFER |
		FORMAT_MESSAGE_FROM_SYSTEM |
		FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL,
		GetLastError(),
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		(LPTSTR)&lpMsgBuf,
		0,
		NULL
	);
	MessageBox(NULL, (LPCTSTR)lpMsgBuf, _T("ERROR"), MB_OK | MB_ICONINFORMATION);
	LocalFree(lpMsgBuf);
}


LRESULT OnCreate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	OutputDebugString(_T("[51asm]: WM_Create\n"));

	// 创建一个定时器,有两种调用方式,100毫秒画一次
// 	SetTimer(hwnd, 1, 1000, nullptr);
// 	SetTimer(hwnd, 2, 1000, nullptr);

	return TRUE;
}

// 当你关闭窗口点击确定后就会向窗口发送WM_Destroy消息,就意味要销毁窗口,
LRESULT OnClose(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	OutputDebugString(_T("[51asm]: WM_Close\n"));
	return FALSE;
}

// 这个工作可以交给系统处理,也可以自己处理
LRESULT OnDestroy(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	OutputDebugString(_T("[51asm]: WM_Destory\n"));
	PostQuitMessage(0);

	// 销毁定时器,倘若有多个窗口,销毁一个窗口而不是全部
	KillTimer(hwnd, 1);


	return TRUE;
}



LRESULT OnCommand(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	OutputDebugString(_T("[51asm] OnCommand\n"));
	WORD wID = LOWORD(wParam);
	WORD wNotifyCode = HIWORD(wParam);
	HWND hColtrol = (HWND)lParam;
	if (hColtrol != NULL) { //控件
		if (wID == IDB_BUTTON1) {
			if (wNotifyCode == BN_CLICKED) {
				LRESULT Result = SendMessage(hColtrol, BM_GETCHECK, 0, 0);
				if (BST_CHECKED == Result) {
					SendMessage(hColtrol, BM_SETCHECK, BST_UNCHECKED, NULL);
					MessageBox(NULL, _T("未婚"), _T("婚姻状况"), MB_OK);
				}
				else if (BST_UNCHECKED == Result) {
					SendMessage(hColtrol, BM_SETCHECK, BST_CHECKED, NULL);
					MessageBox(NULL, _T("已婚"), _T("婚姻状况"), MB_OK);
				}
			}
		}
		else if (wID == IDB_BUTTON2) {
			if (wNotifyCode == BN_CLICKED) {
				HWND hEdit = GetDlgItem(hwnd, IDE_Edit1);
				char szText[] = { "" };
				SendMessage(hEdit, WM_SETTEXT, 0, (LPARAM)szText); // 直接调用窗口过程函数,知道过程函数返回,否则就会一直卡在这里
				SendMessage(hEdit, WM_PASTE, 0, 0);
			}
		}
		
		if (wID == IDL_LISTBOX && wNotifyCode == LBN_SELCHANGE) {
			int nIndex = SendMessage(hColtrol, LB_GETCURSEL, 0, 0);
			if (nIndex != -1) {
				int nLen = SendMessage(hColtrol, LB_GETTEXTLEN, nIndex, 0);
				LPVOID lpBuff = malloc(nLen+1);
				SendMessage(hColtrol, LB_GETTEXT, nIndex, (LPARAM)lpBuff);
				MessageBoxA(hwnd, (char*)lpBuff, "51asm", MB_OK);
				free(lpBuff);
			}
		}
		return TRUE;
	}

	switch (wID) {
	case IDM_OPEN:
		MessageBox(NULL, _T("打开"), _T("51asm"), MB_OK);
		break;
	case IDM_SAVE:
		MessageBox(NULL, _T("保存"), _T("51asm"), MB_OK);
	case IDM_EXIT:
		SendMessage(hwnd, WM_USER + 1, NULL, NULL);// 向窗口发送一个消息
		PostQuitMessage(0); // 给自己投递QUIT消息
		// 操作窗口,想窗口发消息  WM_USER 0x0400开始
		//SendMessage(hwnd,WM_USER+1,NULL,NULL);// 向窗口发送一个消息
		break;
	}
	
	return TRUE;
}


BOOL InitControl(HWND hWnd) {
	// 创建子窗口(控件)控件的操作都会产生Command消息
	HWND hButton1 = CreateWindowEx(0,
		_T("BUTTON"),
		_T("是否打勾"),
		WS_CHILD | WS_VISIBLE | BS_CHECKBOX | LBS_NOTIFY,  //组合属性,可拉伸窗口
		0,
		0,
		100,
		50,
		hWnd,
		(HMENU)IDB_BUTTON1,
		g_hInstance,
		NULL);

	HWND hButton2 = CreateWindowEx(0,
		_T("BUTTON"),
		_T("粘贴"),
		WS_CHILD | WS_VISIBLE, // 还可以给按加别的样式BS_开头
		100,                    //按钮可打勾
		0,
		100,
		50,
		hWnd,
		(HMENU)IDB_BUTTON2,
		g_hInstance,
		NULL);

	HWND hEdit = CreateWindowEx(0,
		_T("Edit"),
		NULL,
		WS_CHILD | WS_VISIBLE | WS_VSCROLL |
		ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL,  //组合属性,可拉伸窗口
		0,     // ws通用 es Edit控件单独有的
		60,
		200,
		100,
		hWnd,
		(HMENU)IDE_Edit1,
		g_hInstance,
		NULL);


	
	HWND hListBox = CreateWindowEx(0,
		_T("ListBox"),
		_T("编程语言列表"),
		WS_CHILD | WS_VISIBLE | WS_VSCROLL | LBS_HASSTRINGS,  //组合属性,可拉伸窗口
		0,     // ws通用 es Edit控件单独有的
		200,
		200,
		100,
		hWnd,
		(HMENU)IDL_LISTBOX,
		g_hInstance,
		NULL);

	SendMessage(hListBox, LB_ADDSTRING, 0, (LPARAM)"C语言");
	SendMessage(hListBox, LB_ADDSTRING, 0, (LPARAM)"C++");
	SendMessage(hListBox, LB_ADDSTRING, 0, (LPARAM)"C数据结构");



	// 操作控件发消息
	SendMessage(hButton1, BM_SETCHECK, BST_UNCHECKED, NULL);
	return TRUE;

}



LRESULT OnKeyDown(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	OutputDebugString(_T("[51asm]: OnKeyDown\n"));
	return TRUE;
}



LRESULT OnKeyUp(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	OutputDebugString(_T("[51asm]: OnKeyUp\n"));
	return TRUE;
}


// 定时器消息
LRESULT OnTimer(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	if (wParam == 1) {
		MYOUTPUT(_T("[51asm]: OnTimer\n"));
		HWND hDesktop = GetDesktopWindow();
		HDC hdc = GetDC(hDesktop);
		TextOut(hdc, 0, 0, _T("51asm"), 5);
		ReleaseDC(hDesktop,hdc);
		//CloseHandle(hDesktop); GetDesktopWinodw()函数的句柄不需要用户释放
		MYOUTPUT(_T("[51asm]: OnTimer ID=1 \n"));
	}
	else if (wParam == 2){
		MYOUTPUT(_T("[51asm]: OnTimer ID=2 \n"));
	}
	return TRUE;
}


LRESULT OnNotify(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	OutputDebugString(_T("[51asm]: OnNotify\n"));
	NMHDR* pnmh = (LPNMHDR)lParam;
	if (wParam == IDL_LISTBOX) {
		int nIndex = SendMessage(pnmh->hwndFrom, LB_GETCURSEL, 0, 0);
		if (nIndex != -1) {
			int nLen = SendMessage(pnmh->hwndFrom, LB_GETTEXTLEN, nIndex, 0);
			LPVOID lpBuff = malloc(nLen);
			SendMessage(pnmh->hwndFrom, LB_GETTEXT, nIndex, (LPARAM)lpBuff);
			MessageBoxA(hwnd, (char*)lpBuff, "51asm", MB_OK);
			free(lpBuff);
		}
	}
	return TRUE;
}



// 消息处理
// 可以下断点debug调试分析消息,在监视这里可以 uMsg.wm 可以以看到
// 先创建非客户区,再创建客户区,还有创建窗口等很多消息
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	LRESULT lResult = FALSE;

	switch (uMsg) {
	case WM_NOTIFY:
		lResult = OnNotify(hwnd, uMsg, wParam, lParam);
		break;
	case WM_CREATE:
		lResult = OnCreate(hwnd, uMsg, wParam, lParam); 
		break;
	case WM_CLOSE:
		lResult = OnClose(hwnd, uMsg, wParam, lParam);
		break;
	case WM_DESTROY:
		lResult = OnDestroy(hwnd, uMsg, wParam, lParam);
		break;
	case WM_COMMAND:   
		lResult = OnCommand(hwnd, uMsg, wParam, lParam);
		break;
	case WM_KEYDOWN:     
		lResult = OnKeyDown(hwnd, uMsg, wParam, lParam);
		break;
	case WM_KEYUP:    
		lResult = OnKeyUp(hwnd, uMsg, wParam, lParam);
		break;
	case WM_TIMER:
		lResult = OnTimer(hwnd, uMsg, wParam, lParam);
		break;
	case MY_MSG:
		MessageBox(NULL, _T("我的消息"), NULL, NULL);
	}

	if (!lResult) {
		return DefWindowProc(hwnd, uMsg, wParam, lParam); // 默认窗口过程处理函数,包括销毁窗口
	}
	return lResult;
}

/*
	客户区(用户区)与非客户区(系统的) NC


*/

int WINAPI wWinMain(
	HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPWSTR lpCmdLine,
	int nShowCmd
) {
	g_hInstance = hInstance;

	// 申请堆控件,因为快捷键需要全局访问
	// 申请100字节的局部堆地址空间
	// 这样设计的原因,内存空间申请释放,产生了很多碎片,通过把这些碎片整理得到一个更大的内存空间,这是地址变化了

	// 申请局部堆地址
	HLOCAL hMenu = LocalAlloc(LHND, 100);
	LPVOID lpMemory = LocalLock(hMenu);
	LocalFree(hMenu);


	// 申请全局堆地址
	// 原因:16位系统,有全局堆和局部堆;32位,两者合并,只有一个堆
	GlobalAlloc(LHND, 100);


	// 申请堆空间
	// 新的API,返回值是一个地址,前两个函数的底层是调用这个
	//HeapAlloc();

	// 申请堆地址空间,可以指定内存属性
	//VirtualAlloc();

	ACCEL* pAccelNews = (ACCEL*)HeapAlloc(GetProcessHeap(), 0, sizeof(ACCEL) * 2);

	if (pAccelNews == nullptr) {
		ShowErrorMsg();
		return 0;
	}
	
	
	// 快捷键,可以用下面的写法,把快捷键和菜单消息一起处理
// 	pAccelNews[0].fVirt = FALT | FCONTROL | FVIRTKEY;
// 	pAccelNews[0].key = 'A';
// 	pAccelNews[0].cmd = WM_COMMAND;

	// 
	pAccelNews[1].fVirt = FCONTROL | FVIRTKEY;
	pAccelNews[1].key = 'S';
	pAccelNews[1].cmd = IDM_SAVE;

	// 创建快捷键表
	HACCEL hAccel = CreateAcceleratorTable(pAccelNews, 2);
	
	if (hAccel == NULL) {
		ShowErrorMsg();
		return 0;
	}


	// 创建窗口实例
	TCHAR szWndClassName[] = { _T("CR41WndClassName") };

	WNDCLASSEX wc = { 0 };
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
	wc.lpfnWndProc = WindowProc;
	wc.hInstance = hInstance;
	wc.hIcon = LoadIcon(NULL, IDI_HAND);
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = CreateSolidBrush(RGB(255, 255, 255));
	wc.lpszMenuName = NULL;
	wc.lpszClassName = szWndClassName;

	// 注册窗口
	if (RegisterClassEx(&wc) == 0) {
		ShowErrorMsg();
		return 0;
	}


	// 创建窗口
	TCHAR szWndName[] = { _T("51asm") };
	HWND hWnd = CreateWindowEx(0,
		szWndClassName,
		szWndName,
		WS_OVERLAPPEDWINDOW,  //组合属性,可拉伸窗口
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		NULL,
		NULL,
		hInstance,
		NULL);



	if (hWnd == NULL) {
		ShowErrorMsg();
		return 0;
	}

	// 菜单
	HMENU HMenu = CreateMenu();

	// 弹出菜单
	BOOL ret;
	ret = AppendMenu(HMenu, MF_STRING | MF_POPUP, (UINT_PTR)HMenu, _T("文件(&F)"));
	ret = AppendMenu(HMenu, MF_STRING | MF_POPUP, (UINT_PTR)HMenu, _T("编辑(&E)"));
	SetMenu(hWnd, HMenu);

	// 添加子菜单
	HMENU hSubMenu = GetSubMenu(HMenu, 0);
	ret = AppendMenu(hSubMenu, MF_STRING, IDM_OPEN, _T("打开(&O)"));
	ret = AppendMenu(hSubMenu, MF_STRING, IDM_SAVE, _T("保存(&O)"));
	ret = AppendMenu(hSubMenu, MF_STRING, IDM_EXIT, _T("退出(&O)"));

	SetMenu(hWnd, HMenu);


	RECT rc;
	GetClientRect(hWnd, &rc);


	// 创建子窗口(控件)
	InitControl(hWnd);



	// 显示,更新窗口
	ShowWindow(hWnd, SW_SHOWNORMAL); // 调用Show时候父子窗口都会被调用
	//ShowWindow(hChild, SW_SHOWNORMAL);  非子窗口需要单独show
	UpdateWindow(hWnd);  // 产生WM_PAINT

	SetClassLong(hWnd, GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_CROSS));




	// 消息循环
	BOOL bRet;
	MSG msg;
	while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
	{
		if (bRet == -1) {
			break;
		}
		else {
			// 转换快捷键消息 WM_COMMAND
			if (!TranslateAccelerator(hWnd, hAccel, &msg)) {
				TranslateMessage(&msg);// 转换键盘消息
				DispatchMessage(&msg); // 派发消息
			}
		}
	}

	// 删除快捷键表
	DestroyAcceleratorTable(hAccel);
	HeapFree(GetProcessHeap(), 0, pAccelNews);

	return msg.wParam;
}

你可能感兴趣的:(SDK,windows,SDK,C++)