《Windows程序设计》读书笔九 子窗口控件
发布日期:2021-05-07 23:35:12 浏览次数:22 分类:原创文章

本文共 54114 字,大约阅读时间需要 180 分钟。

第九章 子窗口控件


子窗口可以作为控制屏幕图形显示,响应用户输入,以及在有重要输入事件的时候通知另一窗口。




标准子窗口控件,按钮,复选框,编辑框,列表框,组合框,文本字符串和滚动条。




可以使用CreateWindow来创建子窗口控件,或者在程序的资源脚本里编辑好各种属性。




使用预定义控件不需要再注册相应的子窗口类,这些类已经存在于windows中并且已经有了预定义的名称。


在调用CreateWindow时,只需要使用该名称作为窗口类的参数即可。




在窗口表明直接创建子窗口,所涉及的任务比使用对话框内的子窗口控件更底层。对于对话框,对话框管理器在你的程序和控件之间增加了一个隔离层。


比如支持TAB,方向键切换焦点。 子窗口控件可以得到输入焦点,可是一旦得到焦点,它就无法把输入焦点交回给其父窗口。




标准控件, 通用控件。




9.1 按钮类



#include <windows.h>    struct  {	int		iStyle;	TCHAR * szText;}button[] = {	BS_PUSHBUTTON,		TEXT("PUSHBUTTON"),	BS_DEFPUSHBUTTON,	TEXT("DEFPUSHBUTTON"),	BS_CHECKBOX,		TEXT("CHECKBOX"),	BS_AUTOCHECKBOX,	TEXT("AUTOCHECKBOX"),	BS_RADIOBUTTON,		TEXT("RADIOBUTTON"),	BS_3STATE,			TEXT("3STATE"),	BS_AUTO3STATE,		TEXT("AUTO3STATE"),	BS_GROUPBOX,		TEXT("GROUPBOX"),	BS_AUTORADIOBUTTON,	TEXT("AUTORADIO"),	BS_OWNERDRAW,		TEXT("OWNERDRAW")};#define NUM (sizeof button / sizeof button[0])LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure.    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,	PSTR szCmdLine, int iCmdShow){	static      TCHAR szAppName[] = TEXT("BtnLook");	HWND        hwnd;	MSG         msg;	WNDCLASS    wndClass;       //The window Class    	wndClass.style = CS_HREDRAW | CS_VREDRAW;	wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class.    	wndClass.cbClsExtra = 0;	wndClass.cbWndExtra = 0;	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 = szAppName;	//Register the Window Class to the Windows System.     	if (!RegisterClass(&wndClass))	{		MessageBox(NULL, TEXT("This program require Windows NT!"),			szAppName, MB_ICONERROR);		return 0;	}	//This function will generate an WM_CREATE message.    	hwnd = CreateWindow(szAppName,      //Window class name    		TEXT("Button Look"),      //Window caption    		WS_OVERLAPPEDWINDOW,            //Window Style    		CW_USEDEFAULT,                  //initial x position    		CW_USEDEFAULT,                  //initial y position    		CW_USEDEFAULT,                  //initial x size    		CW_USEDEFAULT,                  //initial y size    		NULL,                           //parent window handle    		NULL,                           //window menu handle    		hInstance,                      //program instance handle    		NULL);                          //creation parameters    	ShowWindow(hwnd, iCmdShow);	UpdateWindow(hwnd); //This function will generate a WM_PAINT message.    						/* The message loop for this program.						if received the WM_QUIT message, the function will return 0.*/	while (GetMessage(&msg, NULL, 0, 0))	{		TranslateMessage(&msg);		DispatchMessage(&msg);	}	return msg.wParam;}//define the Window Procedure WndProc    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){	static HWND		hwndButton[NUM];	static RECT		rect;	static TCHAR	szTop[] =		TEXT("message            wParam       lParam"),					szUnd[] =		TEXT("_______            ______       ______"),					szFormat[] =	TEXT("%-16s%04X-%04X    %04X-%04X"),					szBuffer[50];	static int		cxChar, cyChar;	HDC				hdc;	PAINTSTRUCT		ps;	int				i;	switch (message) //get the message    	{	case WM_CREATE:		cxChar = LOWORD(GetDialogBaseUnits());		cyChar = HIWORD(GetDialogBaseUnits());		for (i = 0; i < NUM; i++)			hwndButton[i] = CreateWindow(TEXT("button"),				button[i].szText,				WS_CHILD | WS_VISIBLE | button[i].iStyle,				cxChar, cyChar * (1 + 2 * i),				20 * cxChar, 7 * cyChar / 4,				hwnd, (HMENU)i,				((LPCREATESTRUCT)lParam)->hInstance, NULL);		return 0;	case WM_SIZE:		rect.left = 24 * cxChar;		rect.top = 2 * cyChar;		rect.right = LOWORD(lParam);		rect.bottom = HIWORD(lParam);		return 0;	case WM_PAINT:		InvalidateRect(hwnd, &rect, TRUE);		hdc = BeginPaint(hwnd, &ps);		SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));		SetBkMode(hdc, TRANSPARENT);		TextOut(hdc, 24 * cxChar, cyChar, szTop, lstrlen(szTop));		TextOut(hdc, 24 * cxChar, cyChar, szUnd, lstrlen(szUnd));		EndPaint(hwnd, &ps);		return 0;	case WM_DRAWITEM:	case WM_COMMAND:		ScrollWindow(hwnd, 0, -cyChar, &rect, &rect);		hdc = GetDC(hwnd);		SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));		TextOut(hdc, 24 * cxChar, cyChar * (rect.bottom / cyChar - 1),			szBuffer,			wsprintf(szBuffer, szFormat,				message == WM_DRAWITEM ? TEXT("WM_DRAWITEM") :										 TEXT("WM_COMMAND"),				HIWORD(wParam), LOWORD(wParam),				HIWORD(lParam), LOWORD(lParam)));		ReleaseDC(hwnd, hdc);		ValidateRect(hwnd, &rect);		break;	case WM_DESTROY:		PostQuitMessage(0);		return 0;	}	return  DefWindowProc(hwnd, message, wParam, lParam);}





9.1.1 创建子窗口




GetDialogBaseUnits 来获得字符默认的字体的宽度和高度。 低位和高位分别是宽度和高度


与GetTextMetrics返回类似的数据




  1.     GetTextMetrics(hdc, &tm);  

  2.     cxChar = tm.tmAveCharWidth;  

  3.     cyChar = tm.tmHeight + tm.tmExternalLeading;  





每个子窗口的ID是唯一的




在WM_CREATE消息中lParam 是一个指向CREATESTRUCT结构的指针。  hInstance是改结构的成员  即 ( (LPCREATESTRUCT)lParam)->hInstance,


或者


 (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE)


9.1.2 子窗口传递信息给父窗口


点击按钮时,子窗口发送WM_COMMAND 消息给父窗口。


LOWORD(wParam)   子窗口ID


HIWORD(wParam) 通知码


lParam    子窗口句柄




通知码定义




通知码6,7 只有当包含 BS_NOTIFY样式时才会启用


子窗口有输入焦点以后,所有的键盘消息都会送到这个子窗口控件,而不是主窗口。按钮控件一旦获得输入焦点,就会忽略所有按键操作,但空格键除外,此时空格键具有和单击鼠标一样的效果。




9.1.3 父窗口传递信息给子窗口






例如父窗口发送 BM_GETCHECK BM_CHECK 给子窗口控件,以获得和设置复选框和单选框的选择状态。


在用鼠标或空格点击窗口时,BM_GETSTATE 和 BM_SETATETE消息反应一个窗口的状态是正常的还是被单击了。


BM_SETSTYLE 允许在创建按钮后改变按钮的样式。




id=GetWindowLong(hwndChild, GWL_ID);




id = GetDlgCtrlID (hwndChild);




hwndChild = GetDlgItem(hwndParent, id);




9.1.4 按钮


按钮控件 ,调用CreateWindow 或者MoveWindow可以改变其大小和位置, 是一个矩形。 按钮上显示文字


BS_PUSHBUTTON


BS_DEFPUSHBUTTON 较重的轮廓


按钮最佳视觉高度是字符高度的 7/4, 而宽度需要额外容纳两个文本




给子窗口发送BM_SETSTATE消息可以模拟按钮状态变化


SendMessage(hwndButton, BM_SETSTATE, 1, 0);   //按钮被按下


SendMessage(hwndButton, BM_SETSTATE, 0, 0);  //按钮回到正常状态


也可以给按钮发送一个BM_GETSTATE消息,子窗口控件返回当前按钮的状态。如果按钮时按下返回TRUE,否则FALSE.




9.1.5 复选框


checkBox


文本通常出现在复选框右侧,如果包含 BS_LEFTTEXT样式,则出现在左侧; 组合BS_RIGHT样式使文本右对齐


BS_CHECKBOX


必须给控件发送一个BM_SETCHECK消息来设置其选中标记。 wParam 设置1 会选中标记, 0则清楚标记。


发送BM_GETCHECK来获得复选框当前的状态。




在处理WM_COMMAND消息的时候


SendMessage((HWND)lParam , BM_SETCHECK, (WPARAM) 


! SendMessage((HWND)lParam, BM_GETCHECK, 0, 0 ), 0 );




BS_AUTOCHECKBOX


按钮本身负责切换选定和取消标记,可以忽略WM_COMMAND消息


在需要按钮状态时


iCheck = (int) SendMessage(hwndButton, BM_GETCHECK, 0, 0 );      //选中为TRUE ,否则为FALSE




另外 BS_3STATE 和  BS_AUTO3STATE 有3种状态   BM_SETCHECK消息射wParam 为 2 表示灰色


复选框最低高度是一个字符高度,最小宽度是现有字符再加2个字符宽度。




9.1.6 单选按钮


任意时刻只有一个按钮可以被按下。


BS_RADIOBUTTON,  BS_AUTORADIOBUTTON(只用于对话框)


在处理WM_COMMAND消息是应该向其发送消息表明其选中


SendMessage((HWND)lParam, BM_SETCHECK, 1, 0);


发送以下消息表明取消选中


SendMessage((HWND)lParam, BM_SETCHECK, 0, 0);




9.1.7 组合框


GroupBox


通常用来包容其他类型的控件




9.1.8  改变按钮文本


可以调用SetWindowText 来改变按钮的文本


SetWindowText(hwnd, pszString); //包括主窗口和子窗口




iLength = GetWindowText(hwnd, pszBuffer, iMaxLength); //获得窗口当前的文本 Caption属性




可以调用函数使程序对可以接受特定文本长度有所准备


iLength = GetWindowTextLength(hwnd);




9.1.9 可见的按钮和启动的按钮


如果创建子窗口未包含WM_VISIBLE 按钮时不可见的,除非调用


ShowWindow(hwndChild, SW_SHOWNORMAL);


如果窗口可见可以隐藏他


ShowWindow(hwndChild, SW_HIDE);


可以调用一下函数判断窗口是否可见


IsWindowVisible(hwndChild);


启用或禁用子窗口


EnableWindow(hwndChild, FALSE);




EnableWindow(hwndChild, TRUE);




调用一下函数判断子窗口是否被启用


IsWindowEnabled(hwndChild);




9.1.10 按钮和输入焦点


子窗口控件获得输入焦点后,父窗口就会失去输入焦点。之后所有的键盘输入将送到子窗口而不是其父窗口。




Windows把输入焦点从一个窗口切换到另一个窗口时,它首先会像要失去输入焦点的窗口发送一条消息WM_KILLFOCUS. 相应的wParam参数是将要获得输入焦点的窗口的句柄。然后Windows向要接受输入焦点的窗口发送WM_SETFOCUS消息,用wParam指定失去输入焦点的窗口的句柄。


父窗口可以通过WM_KILLFOCUS消息来阻止子窗口控件获得输入焦点。



	case WM_KILLFOCUS:		for (i = 0; i < NUM; i++)			if (hwndButton[i] == (HWND)wParam)			{				SetFocus(hwnd);				break;			}
这样子窗口将不会获得输入焦点


或者



	case WM_KILLFOCUS:		if (hwnd == GetParent((HWND)wParam))			SetFocus(hwnd);


单这么做以后按钮将不能再响应消息。因为按钮从未得到输入焦点。


9.2 控件和颜色


9.2.1 系统颜色


windows有29种系统颜色来支持各部分显示。可以使用GetSysColor 和SetSysColor获取并设置这些颜色。










9.2.2 按钮的颜色


COLOR_BTNFACE  按钮表面


COLOR_BTNSHADOW 用于按钮底部和右侧,复选框方块的内部和单选按钮的圆圈内,用来表示阴影。


COLOR_BTNTEXT 文本颜色


COLOR_WINDOWTEXT 其他控件文本颜色


为了在客户区表面显示按钮,首先选用COLOR_BTNFACE作为客户区的背景颜色




wndClass.hbrBackground = (HBRUSH) (COLOR_BTNFACE+1); //为了防止出现NULL值




TextOut显示文本时,windows使用设备环境中定义的值作为文本背景色,预设是白色背景  黑色文本。


SetTextColor  SetBkColor  改变文办颜色和背景颜色




SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));


SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));


如果用户更改了系统颜色,则需要更改文办的背景颜色和文办颜色


case WM_SYSCOLORCHANGE:


InvalidateRect(hwnd, NULL, TRUE);


        break;




修改后的Button Look 程序



#include <windows.h>    struct  {	int		iStyle;	TCHAR * szText;}button[] = {	BS_PUSHBUTTON,		TEXT("PUSHBUTTON"),	BS_DEFPUSHBUTTON,	TEXT("DEFPUSHBUTTON"),	BS_CHECKBOX,		TEXT("CHECKBOX"),	BS_AUTOCHECKBOX,	TEXT("AUTOCHECKBOX"),	BS_RADIOBUTTON,		TEXT("RADIOBUTTON"),	BS_3STATE,			TEXT("3STATE"),	BS_AUTO3STATE,		TEXT("AUTO3STATE"),	BS_GROUPBOX,		TEXT("GROUPBOX"),	BS_AUTORADIOBUTTON,	TEXT("AUTORADIO"),	BS_OWNERDRAW,		TEXT("OWNERDRAW")};#define NUM (sizeof button / sizeof button[0])LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure.    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,	PSTR szCmdLine, int iCmdShow){	static      TCHAR szAppName[] = TEXT("BtnLook");	HWND        hwnd;	MSG         msg;	WNDCLASS    wndClass;       //The window Class    	wndClass.style = CS_HREDRAW | CS_VREDRAW;	wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class.    	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_BTNFACE + 1);//(HBRUSH)GetStockObject(WHITE_BRUSH);	wndClass.lpszMenuName = NULL;	wndClass.lpszClassName = szAppName;	//Register the Window Class to the Windows System.     	if (!RegisterClass(&wndClass))	{		MessageBox(NULL, TEXT("This program require Windows NT!"),			szAppName, MB_ICONERROR);		return 0;	}	//This function will generate an WM_CREATE message.    	hwnd = CreateWindow(szAppName,      //Window class name    		TEXT("Button Look"),      //Window caption    		WS_OVERLAPPEDWINDOW,            //Window Style    		CW_USEDEFAULT,                  //initial x position    		CW_USEDEFAULT,                  //initial y position    		CW_USEDEFAULT,                  //initial x size    		CW_USEDEFAULT,                  //initial y size    		NULL,                           //parent window handle    		NULL,                           //window menu handle    		hInstance,                      //program instance handle    		NULL);                          //creation parameters    	ShowWindow(hwnd, iCmdShow);	UpdateWindow(hwnd); //This function will generate a WM_PAINT message.    						/* The message loop for this program.						if received the WM_QUIT message, the function will return 0.*/	while (GetMessage(&msg, NULL, 0, 0))	{		TranslateMessage(&msg);		DispatchMessage(&msg);	}	return msg.wParam;}//define the Window Procedure WndProc    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){	static HWND		hwndButton[NUM];	static RECT		rect;	static TCHAR	szTop[] =		TEXT("message            wParam       lParam"),					szUnd[] =		TEXT("_______            ______       ______"),					szFormat[] =	TEXT("%-16s%04X-%04X    %04X-%04X"),					szBuffer[50];	static int		cxChar, cyChar;	HDC				hdc;	PAINTSTRUCT		ps;	int				i;	switch (message) //get the message    	{	case WM_CREATE:		cxChar = LOWORD(GetDialogBaseUnits());		cyChar = HIWORD(GetDialogBaseUnits());		for (i = 0; i < NUM; i++)			hwndButton[i] = CreateWindow(TEXT("button"),				button[i].szText,				WS_CHILD | WS_VISIBLE | button[i].iStyle,				cxChar, cyChar * (1 + 2 * i),				20 * cxChar, 7 * cyChar / 4,				hwnd, (HMENU)i,				(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE)/*((LPCREATESTRUCT)lParam)->hInstance*/, NULL);		return 0;	case WM_SIZE:		rect.left = 24 * cxChar;		rect.top = 2 * cyChar;		rect.right = LOWORD(lParam);		rect.bottom = HIWORD(lParam);		return 0;	case WM_SYSCOLORCHANGE:		InvalidateRect(hwnd, NULL, TRUE);		break;	case WM_PAINT:		InvalidateRect(hwnd, &rect, TRUE);		hdc = BeginPaint(hwnd, &ps);		SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));		SetBkMode(hdc, TRANSPARENT);		SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));		SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));		TextOut(hdc, 24 * cxChar, cyChar, szTop, lstrlen(szTop));		TextOut(hdc, 24 * cxChar, cyChar, szUnd, lstrlen(szUnd));		EndPaint(hwnd, &ps);		return 0;	case WM_DRAWITEM:	case WM_COMMAND:		ScrollWindow(hwnd, 0, -cyChar, &rect, &rect);		hdc = GetDC(hwnd);		SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));		SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));		SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));		TextOut(hdc, 24 * cxChar, cyChar * (rect.bottom / cyChar - 1),			szBuffer,			wsprintf(szBuffer, szFormat,				message == WM_DRAWITEM ? TEXT("WM_DRAWITEM") :										 TEXT("WM_COMMAND"),				HIWORD(wParam), LOWORD(wParam),				HIWORD(lParam), LOWORD(lParam)));		switch(LOWORD(wParam))			{		case 0:			EnableWindow(hwndButton[1], FALSE);			break;		case 2://checkbox			SendMessage((HWND)lParam, BM_SETCHECK, (WPARAM)				!SendMessage((HWND)lParam, BM_GETCHECK, 0, 0), 0);			break;		case 4://Radiobutton			SendMessage((HWND)lParam, BM_SETCHECK, 1, 0);			break;		}		ReleaseDC(hwnd, hdc);		ValidateRect(hwnd, &rect);		break;	case WM_DESTROY:		PostQuitMessage(0);		return 0;	}	return  DefWindowProc(hwnd, message, wParam, lParam);}









9.2.3 WM_CTLCOLORBTN 消息


最好不要用SetSysColors改变按钮外观,这将改变windows环境下正在运行的所有程序


或者重载WM_CTLCOLORBTN消息,当子窗口需要重绘时按钮会把这个消息发给父窗口。可以利用这个机会来改变子窗口颜色


当父窗口收到WM_CTLCOLORBTN消息时,wParam是子窗口的设备环境句柄,lParam是子窗口句柄。


SetTextColor 设置文本颜色


SetBkColor 设置文本背景色


返回子窗口的画刷句柄 子窗口使用这个画刷来着色背景。在不需要画刷时,你需要负责销毁画刷。


9.2.4 自绘按钮



#include <windows.h>    #define ID_SMALLER	1#define ID_LARGER	2#define BTN_WIDTH	(8 * cxChar)#define BTN_HEIGHT	(4 * cyChar)LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure.    HINSTANCE hInst;int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,	PSTR szCmdLine, int iCmdShow){	static      TCHAR szAppName[] = TEXT("OwnDraw");	HWND        hwnd;	MSG         msg;	WNDCLASS    wndClass;       //The window Class    	hInst = hInstance;	wndClass.style = CS_HREDRAW | CS_VREDRAW;	wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class.    	wndClass.cbClsExtra = 0;	wndClass.cbWndExtra = 0;	wndClass.hInstance = hInstance;	wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);	wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);	wndClass.lpszMenuName = szAppName;	wndClass.lpszClassName = szAppName;	//Register the Window Class to the Windows System.     	if (!RegisterClass(&wndClass))	{		MessageBox(NULL, TEXT("This program require Windows NT!"),			szAppName, MB_ICONERROR);		return 0;	}	//This function will generate an WM_CREATE message.    	hwnd = CreateWindow(szAppName,      //Window class name    		TEXT("Owner-Draw Button Demo"),      //Window caption    		WS_OVERLAPPEDWINDOW,            //Window Style    		CW_USEDEFAULT,                  //initial x position    		CW_USEDEFAULT,                  //initial y position    		CW_USEDEFAULT,                  //initial x size    		CW_USEDEFAULT,                  //initial y size    		NULL,                           //parent window handle    		NULL,                           //window menu handle    		hInstance,                      //program instance handle    		NULL);                          //creation parameters    	ShowWindow(hwnd, iCmdShow);	UpdateWindow(hwnd); //This function will generate a WM_PAINT message.    						/* The message loop for this program.						if received the WM_QUIT message, the function will return 0.*/	while (GetMessage(&msg, NULL, 0, 0))	{		TranslateMessage(&msg);		DispatchMessage(&msg);	}	return msg.wParam;}void Triangle(HDC hdc, POINT pt[]){	SelectObject(hdc, GetStockObject(BLACK_BRUSH));	Polygon(hdc, pt, 3);	SelectObject(hdc, GetStockObject(WHITE_BRUSH));}//define the Window Procedure WndProc    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){	static HWND			hwndSmaller, hwndLarger;	static int			cxClient, cyClient, cxChar, cyChar;	int					cx, cy;	LPDRAWITEMSTRUCT	pdis;	POINT				pt[3];	RECT				rc;	switch (message) //get the message    	{	case WM_CREATE:		cxChar = LOWORD(GetDialogBaseUnits());		cyChar = HIWORD(GetDialogBaseUnits());		//Create the owner-draw pushbuttons		hwndSmaller = CreateWindow(TEXT("button"), TEXT(""),			WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,			0, 0, BTN_WIDTH, BTN_HEIGHT,			hwnd, (HMENU) ID_SMALLER,			(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL);		hwndLarger = CreateWindow(TEXT("button"), TEXT(""),			WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,			0, 0, BTN_WIDTH, BTN_HEIGHT,			hwnd, (HMENU)ID_LARGER,			((LPCREATESTRUCT)lParam)->hInstance, NULL);					return 0;	case WM_SIZE:		cxClient = LOWORD(lParam);		cyClient = HIWORD(lParam);		//Move the buttons to the new center		MoveWindow(hwndSmaller, cxClient / 2 - 3 * BTN_WIDTH / 2,								cyClient / 2 - BTN_HEIGHT / 2,								BTN_WIDTH, BTN_HEIGHT, TRUE);		MoveWindow(hwndLarger, cxClient / 2 + BTN_WIDTH / 2,							   cyClient / 2 - BTN_HEIGHT / 2,							   BTN_WIDTH, BTN_HEIGHT, TRUE);		return 0;	case WM_COMMAND:		GetWindowRect(hwnd, &rc);		//Make the wnidow 10% smaller or larger		switch (wParam)		{		case ID_SMALLER:			rc.left += cxClient / 20;			rc.right -= cxClient / 20;			rc.top += cyClient / 20;			rc.bottom -= cyClient / 20;			break;		case ID_LARGER:			rc.left -= cxClient / 20;			rc.right += cxClient / 20;			rc.top -= cyClient / 20;			rc.bottom += cyClient / 20;		}		MoveWindow(hwnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);		return 0;	case WM_DRAWITEM:		pdis = (LPDRAWITEMSTRUCT)lParam;		FillRect(pdis->hDC, &pdis->rcItem,			(HBRUSH)GetStockObject(WHITE_BRUSH));		FrameRect(pdis->hDC, &pdis->rcItem,			(HBRUSH)GetStockObject(BLACK_BRUSH));		//Draw inward and outward black triangles		cx = pdis->rcItem.right - pdis->rcItem.left;		cy = pdis->rcItem.bottom - pdis->rcItem.top;		switch (pdis->CtlID)		{		case ID_SMALLER:			pt[0].x = 3 * cx / 8;  pt[0].y = 1 * cy / 8;			pt[1].x = 5 * cx / 8;  pt[1].y = 1 * cy / 8;			pt[2].x = 4 * cx / 8;  pt[2].y = 3 * cy / 8;			Triangle(pdis->hDC, pt);			pt[0].x = 7 * cx / 8;  pt[0].y = 3 * cy / 8;			pt[1].x = 7 * cx / 8;  pt[1].y = 5 * cy / 8;			pt[2].x = 5 * cx / 8;  pt[2].y = 4 * cy / 8;			Triangle(pdis->hDC, pt);			pt[0].x = 5 * cx / 8;  pt[0].y = 7 * cy / 8;			pt[1].x = 3 * cx / 8;  pt[1].y = 7 * cy / 8;			pt[2].x = 4 * cx / 8;  pt[2].y = 5 * cy / 8;			Triangle(pdis->hDC, pt);			pt[0].x = 1 * cx / 8;  pt[0].y = 5 * cy / 8;			pt[1].x = 1 * cx / 8;  pt[1].y = 3 * cy / 8;			pt[2].x = 3 * cx / 8;  pt[2].y = 4 * cy / 8;			Triangle(pdis->hDC, pt);			break;		case ID_LARGER:			pt[0].x = 5 * cx / 8;  pt[0].y = 3 * cy / 8;			pt[1].x = 3 * cx / 8;  pt[1].y = 3 * cy / 8;			pt[2].x = 4 * cx / 8;  pt[2].y = 1 * cy / 8;			Triangle(pdis->hDC, pt);			pt[0].x = 5 * cx / 8;  pt[0].y = 5 * cy / 8;			pt[1].x = 5 * cx / 8;  pt[1].y = 3 * cy / 8;			pt[2].x = 7 * cx / 8;  pt[2].y = 4 * cy / 8;			Triangle(pdis->hDC, pt);			pt[0].x = 3 * cx / 8;  pt[0].y = 5 * cy / 8;			pt[1].x = 5 * cx / 8;  pt[1].y = 5 * cy / 8;			pt[2].x = 4 * cx / 8;  pt[2].y = 7 * cy / 8;			Triangle(pdis->hDC, pt);			pt[0].x = 3 * cx / 8;  pt[0].y = 3 * cy / 8;			pt[1].x = 3 * cx / 8;  pt[1].y = 5 * cy / 8;			pt[2].x = 1 * cx / 8;  pt[2].y = 4 * cy / 8;			Triangle(pdis->hDC, pt);			break;		}				//Invert the rectangle if the button is selected		if (pdis->itemState & ODS_SELECTED)			InvertRect(pdis->hDC, &pdis->rcItem);		//Draw a focus rectangle if the button has the focus		if (pdis->itemState & ODS_FOCUS)		{			pdis->rcItem.left += cx / 16;			pdis->rcItem.top += cy / 16;			pdis->rcItem.right -= cx / 16;			pdis->rcItem.bottom -= cy / 16;			DrawFocusRect(pdis->hDC, &pdis->rcItem);		}		return 0;	case WM_DESTROY:		PostQuitMessage(0);		return 0;	}	return  DefWindowProc(hwnd, message, wParam, lParam);}


该例子绘制了两个按钮,点击能分别扩大和缩小窗口客户区的尺寸




在按钮上显示图标或位图,可以使用BS_ICON 或者BS_BITMAP样式。 设置位图可以使用BM_SETIMAGE消息。


但BS_OWNERDRAW允许你完全自己绘制按钮。


GetWindowRect存储整个客户区的矩形区域,位置是相对屏幕的坐标




DRAWITEMSTRUCT结构中与绘制按钮相关的字段


hDC 按钮设备环境


rcItem RECT结构


CtlID 控件的ID


itemState 按钮是否按下或者有输入焦点




InvertRect 用来颠倒矩形区域的颜色  ODS_SELECTED


DrawFocusRect   绘制焦点框  ODS_FOCUS




9.3  静态类


使用CreateWindow函数和静态窗口类来创建静态子窗口控件。


当单机静态子窗口时,会获得WM_NCHITTEST消息, 并向windows返回HITTRANSPARENT值。 通常交给DefWindowProc处理


静态窗口样式


SS_BLACKRECT SS_BLACKFRAME


SS_GRAYRECT SS_GRAYFRAME


SS_WHITERECT SS_WHITEFRAME


基于下表所显示的系统颜色




CreateWindow 调用的窗口文本字段将被忽略。 矩形左上角坐标是相对父窗口。 可以使用SS_ETCHEDHORZ, SS_ETCHEDVERT  或者SS_ETCHEDFRAME样式来用白色和灰色创建一个阴影框架


静态类包含三个文本样式: SS_LEFT, SS_RIGHT 和 SS_CENTER。 这样会创建左对齐,右对齐和居中的文本。 文本右CreateWindow函数窗口文本参数确定


可以使用SetWindowText修改。  当静态类显示文本时,会使用DT_WORDBREAK, DT_NOCLIP 和  DT_EXPANDTABS等参数来调用DrawText函数。


子窗口矩形框具有文本自动换行功能。


这三种样式的背景颜色通常是 COLOR_BTNFACE,   文本颜色是  COLOR_WINDOWTEXT.  


可以复WM_COLORSTATIC消息,调用SetTextColor 和SetBkColor 分别改变文本颜色和背景颜色,同时返回背景画刷句柄。


静态类还有两个样式  SS_ICON  SS_USERITEM 然后当它用作子窗口控件,这些样式时无效的。




9.4  滚动条类


滚动条不发送WM_COMMAND消息到父窗口。  他发送WM_VSCROLL 和  WM_HSCROLL  lParam参数区分窗口滚动条和滚动条控件。   lParam为0  就是窗口滚动条


如果等于滚动条窗口句柄,就是滚动条空降 wParam  高位和低位对于窗口滚动条和滚动条控件含义是一样的


可以使用MoveWindow 或者CreateWindow来设定滚动条控件的大小。


可以使用GetSystemMetrics(SM_CYHSCROLL)   水平滚动条的高度


GetSystemMetrics(SM_CXVSCROLL); 垂直滚动条的宽度


滚动条窗口样式标识符  SBS_LEFTALIGN,  SBS_RIGHTALIGN,  SBS_TOPALIGN 和  SBS_BOTTOMALIGN  都为滚动条提供标准尺寸。


SetScrollRange(hwndScroll, SB_CTL, iMin, iMax, bRedraw);


SetScrollPos(hwndScroll, SB_CTL, iPos, bRedraw);


SetScrollInfo(hwndScroll, SB_CTL, &si, bRedraw);


滚动条两端按钮颜色基于 COLOR_BTNFACE, COLOR_BTNHILIGHT,  COLOR_BTNSHADOW, COLOR_BTNTEXT(给小箭头使用),COLOR_DKSHADOW 以及COLOR_BTNLIGHT.


两端按钮之间的大片区域基于  COLOR_BTNFACE和 COLOR_BTNHILIGHT的某种组合。


如果俘获了WM_CTLCOLORSCROLLBAR消息,就可以从这个消息返回一个画刷来改变原理的颜色。




9.4.1 COLORS1 程序





#include <windows.h>    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure.  LRESULT CALLBACK ScrollProc(HWND, UINT, WPARAM, LPARAM);int		idFocus;WNDPROC OldScroll[3];int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,	PSTR szCmdLine, int iCmdShow){	static      TCHAR szAppName[] = TEXT("Colors1");	HWND        hwnd;	MSG         msg;	WNDCLASS    wndClass;       //The window Class    	wndClass.style = CS_HREDRAW | CS_VREDRAW;	wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class.    	wndClass.cbClsExtra = 0;	wndClass.cbWndExtra = 0;	wndClass.hInstance = hInstance;	wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);	wndClass.hbrBackground = CreateSolidBrush(0);//(HBRUSH)GetStockObject(WHITE_BRUSH);	wndClass.lpszMenuName = NULL;	wndClass.lpszClassName = szAppName;	//Register the Window Class to the Windows System.     	if (!RegisterClass(&wndClass))	{		MessageBox(NULL, TEXT("This program require Windows NT!"),			szAppName, MB_ICONERROR);		return 0;	}	//This function will generate an WM_CREATE message.    	hwnd = CreateWindow(szAppName,      //Window class name    		TEXT("Color Scroll"),      //Window caption    		WS_OVERLAPPEDWINDOW,            //Window Style    		CW_USEDEFAULT,                  //initial x position    		CW_USEDEFAULT,                  //initial y position    		CW_USEDEFAULT,                  //initial x size    		CW_USEDEFAULT,                  //initial y size    		NULL,                           //parent window handle    		NULL,                           //window menu handle    		hInstance,                      //program instance handle    		NULL);                          //creation parameters    	ShowWindow(hwnd, iCmdShow);	UpdateWindow(hwnd); //This function will generate a WM_PAINT message.    						/* The message loop for this program.						if received the WM_QUIT message, the function will return 0.*/	while (GetMessage(&msg, NULL, 0, 0))	{		TranslateMessage(&msg);		DispatchMessage(&msg);	}	return msg.wParam;}//define the Window Procedure WndProc    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){	static COLORREF	crPrim[3] = { RGB(255, 0, 0), RGB(0, 255, 0), RGB(0, 0, 255) };	static HBRUSH	hBrush[3], hBrushStatic;	static HWND		hwndScroll[3], hwndLabel[3], hwndValue[3], hwndRect;	static int		color[3], cyChar;	static RECT		rcColor;	static TCHAR *	szColorLabel[] = { TEXT("Red"), TEXT("Green"), TEXT("Blue") };	HINSTANCE		hInstance;	int				i, cxClient, cyClient;	TCHAR			szBuffer[10];	switch (message) //get the message    	{	case WM_CREATE:		hInstance = (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE);		//Create the white-rectangle window against which the		//scroll bars will be positioned. The child window ID is 9.		hwndRect = CreateWindow(TEXT("static"), NULL,			WS_CHILD | WS_VISIBLE | SS_WHITERECT,			0, 0, 0, 0,			hwnd, (HMENU) 9,			hInstance, NULL);		for (i = 0; i < 3; i++)		{			//The three scroll bars have IDs 0, 1, and 2, with			//scroll bar ranges from 0 through 255.			hwndScroll[i] = CreateWindow(TEXT("scrollbar"), NULL,				WS_CHILD | WS_VISIBLE | WS_TABSTOP | SBS_VERT,				0, 0, 0, 0,				hwnd, (HMENU) i,				hInstance, NULL);			SetScrollRange(hwndScroll[i], SB_CTL, 0, 255, FALSE);			SetScrollPos  (hwndScroll[i], SB_CTL, 0, FALSE);			//The three color-name labels have IDs 3, 4, and 5,			//and text strings "Red", "Green", "Blue".			hwndLabel[i] = CreateWindow(TEXT("static"), szColorLabel[i],				WS_CHILD | WS_VISIBLE | SS_CENTER,				0, 0, 0, 0,				hwnd, (HMENU) (i + 3),				hInstance, NULL);			//The three color-value text fields have Ids 6, 7,			//and 8, and initial text strings of "0".			hwndValue[i] = CreateWindow(TEXT("static"), TEXT("0"),				WS_CHILD | WS_VISIBLE | SS_CENTER,				0, 0, 0, 0,				hwnd, (HMENU)(i + 6),				hInstance, NULL);			OldScroll[i] = (WNDPROC)SetWindowLong(hwndScroll[i], GWL_WNDPROC, (LONG)ScrollProc); //Register the windowproc to sub windows.			hBrush[i] = CreateSolidBrush(crPrim[i]);		}		hBrushStatic = CreateSolidBrush(GetSysColor(COLOR_BTNHIGHLIGHT));		cyChar = HIWORD(GetDialogBaseUnits());					return 0;	case WM_SIZE:		cxClient = LOWORD(lParam);		cyClient = HIWORD(lParam);		SetRect(&rcColor, cxClient / 2, 0, cxClient, cyClient);		MoveWindow(hwndRect, 0, 0, cxClient / 2, cyClient, TRUE);		for (i = 0; i < 3; i++)		{			MoveWindow(hwndScroll[i],				(2 * i + 1) * cxClient / 14, 2 * cyChar,				cxClient / 14, cyClient - 4 * cyChar, TRUE);			MoveWindow(hwndLabel[i],				(4 * i + 1) * cxClient / 28, cyChar / 2,				cxClient / 7, cyChar, TRUE);			MoveWindow(hwndValue[i],				(4 * i + 1) * cxClient / 28, cyClient - 3 * cyChar / 2,				cxClient / 7, cyChar, TRUE);		}		SetFocus(hwnd);		return 0;	case WM_SETFOCUS:		SetFocus(hwndScroll[idFocus]);		return 0;	case WM_VSCROLL:		i = GetWindowLong((HWND)lParam, GWL_ID);		switch (LOWORD(wParam))		{		case SB_PAGEDOWN:			color[i] += 15;			//fall through		case SB_LINEDOWN:			color[i] = min(255, color[i] + 1);			break;		case SB_PAGEUP:			color[i] -= 15;			//fall through		case SB_LINEUP:			color[i] = max(0, color[i] - 1);			break;		case SB_TOP:			color[i] = 0;			break;		case SB_BOTTOM:			color[i] = 255;			break;		case SB_THUMBPOSITION:		case SB_THUMBTRACK:			color[i] = HIWORD(wParam);			break;		default:			break;		}		SetScrollPos(hwndScroll[i], SB_CTL, color[i], TRUE);		wsprintf(szBuffer, TEXT("%i"), color[i]);		SetWindowText(hwndValue[i], szBuffer);		DeleteObject((HBRUSH)			SetClassLong(hwnd, GCL_HBRBACKGROUND, (LONG)				CreateSolidBrush(RGB(color[0], color[1], color[2]))));		InvalidateRect(hwnd, &rcColor, TRUE);		return 0;	case WM_CTLCOLORSCROLLBAR:		i = GetWindowLong((HWND)lParam, GWL_ID);		return (LRESULT)hBrush[i];	case WM_CTLCOLORSTATIC:		i = GetWindowLong((HWND)lParam, GWL_ID);		if (i >= 3 && i <= 8) // static text controls		{			SetTextColor((HDC)wParam, crPrim[i % 3]);			SetBkColor((HDC)wParam, GetSysColor(COLOR_BTNHIGHLIGHT));			return (LRESULT)hBrushStatic;		}		break;	case WM_SYSCOLORCHANGE:		DeleteObject(hBrushStatic);		hBrushStatic = CreateSolidBrush(GetSysColor(COLOR_BTNHIGHLIGHT));		return 0;	case WM_DESTROY:		DeleteObject((HBRUSH)			SetClassLong(hwnd, GCL_HBRBACKGROUND, (LONG)				GetStockObject((WHITE_BRUSH))));		for (i = 0; i < 3; i++)			DeleteObject(hBrush[i]);		DeleteObject(hBrushStatic);		PostQuitMessage(0);		return 0;	}	return  DefWindowProc(hwnd, message, wParam, lParam);}LRESULT CALLBACK ScrollProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){	int id = GetWindowLong(hwnd, GWL_ID);	switch (message)	{	case WM_KEYDOWN:		if (wParam == VK_TAB)			SetFocus(GetDlgItem(GetParent(hwnd),			(id + (GetKeyState(VK_SHIFT) < 0 ? 2 : 1)) % 3));		break;	case WM_SETFOCUS:		idFocus = id;		break;	}	return CallWindowProc(OldScroll[id], hwnd, message, wParam, lParam);}
运行结果





9.4.2  自动键盘接口




在CreateWindow 中加入WS_TABSTOP 标识符。当滚动条获得输入焦点时,滚动条上会显示一个闪烁的灰色快。


父窗口在获得焦点以后要捕获WM_SETFOCUS消息,并传递给子窗口  


SetFocus(hwndScroll[idFocus]);




9.4.3 窗口子类


滚动条类的窗口过程在windows内部


。 但是可以调用GetWindowLong来获取地址使用GWL_WNDPROC标识符作为参数即可。还可以调用SetWindowLong 为滚动条设置一个新的窗口过程,  称为窗口子类。


OldScroll[i] = (WNDPROC)SetWindowLong(hwndScroll[i], GWL_WNDPROC, (LONG)ScrollProc); //Register the windowproc to sub windows.


设置新的滚动条窗口过程,并且保留现有滚动条窗口过程的地址。




9.4.4 背景颜色


使用GetClassWord 和SetClassWord来获取和设置窗口背景画刷的句柄。


你可以创建新的画刷,把句柄存入到窗口类的结构中,然后删除旧的画刷



		DeleteObject((HBRUSH)			SetClassLong(hwnd, GCL_HBRBACKGROUND, (LONG)				CreateSolidBrush(RGB(color[0], color[1], color[2]))));


下次windows重绘窗口时,就会使用这个新的画刷




可以强制让windows擦除背景


InvalidateRect(hwnd, &rcColor, TRUE);




UpdateWindow(hwnd); 立即更新  不过可能会拖慢键盘和鼠标处理速度。




在处理WM_DESTORY消息时, 删除当前创建的画刷



		DeleteObject((HBRUSH)			SetClassLong(hwnd, GCL_HBRBACKGROUND, (LONG)				GetStockObject((WHITE_BRUSH))));


9.4.5 给滚动条和静态文本着色


滚动条着色是通过处理  WM_CTLCOLORSCROLLBAR消息来完成的。


返回一个已经创建的画刷   return (LRESULT) hBrush[i];


这些画刷必须在WM_DESTROY消息期间被销毁


for(i = 0; i < 3; i++)


    DeleteObject(hBrush[i]);




静态文本框颜色是通通过WM_CTLCOLORSTATIC消息和调用SetTextColor完成。 文本背景调用SetBkColor设置为  COLOR_BTNHIGHLIGHT,但该颜色仅限制于显示文字的区域。同时返回一个hBrushStatic 设置静态文本窗口的整个背景颜色。




为了防止系统颜色改变


在WM_SYSCOLORCHANGE消息时用心颜色重新创建hBrushStatic.




9.5 编辑类




POPPAD1



#include <windows.h>    #define ID_EDIT	1LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure.  TCHAR	szAppName[] = TEXT("PopPad1");int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,	PSTR szCmdLine, int iCmdShow){	//static      TCHAR szAppName[] = TEXT("Colors1");	HWND        hwnd;	MSG         msg;	WNDCLASS    wndClass;       //The window Class    	wndClass.style = CS_HREDRAW | CS_VREDRAW;	wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class.    	wndClass.cbClsExtra = 0;	wndClass.cbWndExtra = 0;	wndClass.hInstance = hInstance;	wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);	wndClass.hbrBackground = CreateSolidBrush(0);//(HBRUSH)GetStockObject(WHITE_BRUSH);	wndClass.lpszMenuName = NULL;	wndClass.lpszClassName = szAppName;	//Register the Window Class to the Windows System.     	if (!RegisterClass(&wndClass))	{		MessageBox(NULL, TEXT("This program require Windows NT!"),			szAppName, MB_ICONERROR);		return 0;	}	//This function will generate an WM_CREATE message.    	hwnd = CreateWindow(szAppName,      //Window class name    		TEXT("PopPad1"),      //Window caption    		WS_OVERLAPPEDWINDOW,            //Window Style    		CW_USEDEFAULT,                  //initial x position    		CW_USEDEFAULT,                  //initial y position    		CW_USEDEFAULT,                  //initial x size    		CW_USEDEFAULT,                  //initial y size    		NULL,                           //parent window handle    		NULL,                           //window menu handle    		hInstance,                      //program instance handle    		NULL);                          //creation parameters    	ShowWindow(hwnd, iCmdShow);	UpdateWindow(hwnd); //This function will generate a WM_PAINT message.    						/* The message loop for this program.						if received the WM_QUIT message, the function will return 0.*/	while (GetMessage(&msg, NULL, 0, 0))	{		TranslateMessage(&msg);		DispatchMessage(&msg);	}	return msg.wParam;}//define the Window Procedure WndProc    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){	static HWND	hwndEdit;	switch (message) //get the message    	{	case WM_CREATE:		hwndEdit = CreateWindow(TEXT("edit"), NULL,			WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL |			WS_BORDER | ES_LEFT | ES_MULTILINE |			ES_AUTOHSCROLL | ES_AUTOVSCROLL,			0, 0, 0, 0,			hwnd, (HMENU)ID_EDIT,			((LPCREATESTRUCT)lParam)->hInstance, NULL);					return 0;	case WM_SETFOCUS:		SetFocus(hwndEdit);		return 0;	case WM_SIZE:		MoveWindow(hwndEdit, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);		return 0;	case WM_COMMAND:		if (LOWORD(wParam) == ID_EDIT)			if (HIWORD(wParam) == EN_ERRSPACE ||				HIWORD(wParam) == EN_MAXTEXT)				MessageBox(hwnd, TEXT("Edit control out of spae."),					szAppName, MB_OK | MB_ICONSTOP);		return 0;	case WM_DESTROY:		PostQuitMessage(0);		return 0;	}	return  DefWindowProc(hwnd, message, wParam, lParam);}
运行结果如下







9.5.1 编辑类的样式


在失去焦点依然保持高亮要选用 ES_NOHIDESEL样式


在POPPAD1 程序创建编辑控件时,相应的样式时在CreateWindow调用中指定的


WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL |
WS_BORDER | ES_LEFT | ES_MULTILINE |
ES_AUTOHSCROLL | ES_AUTOVSCROLL




编辑控件的尺寸是在收到WM_SIZE以后调用MoveWindow设置的


MoveWindow(hwndEdit, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);




9.5.2 编辑控件的通知消息




9.5.3 使用编辑控件


如果使用了多个编辑控件,需要拦截TAB消息或者SHIFT TAB来实现焦点切换。


使用SetWindowText 像编辑框插入内容。 从编辑控件读取文本使用GetWindowTextLength 和GetWindowText




9.5.4 传递给编辑控件的消息


SendMessage(hwndEdit, WM_CUT, 0, 0 );


SendMessage(hwndEdit, WM_COPY, 0, 0 );


SendMessage(hwndEdit, WM_CLEAR, 0, 0);




WM_CUT消息把当前选择从编辑控件中移走并发送给剪贴板。


WM_COPY 把当前选择从编辑框控件拷贝到剪贴板


WM_CLEAR 把当前选择从编辑控件删除并且不传递给剪贴板




SendMessage(hwndEdit, WM_PASTE, 0, 0);


把剪贴板上的文本插入到编辑控件的当前位置


使用如下函数获得当前选择文本的出师位置和终止位置


SendMesssage(hwndEdit, EM_GETSEL, (WPARAM)&iSart, (LPARAM) &iEnd);


终止位置是你选择最后一个字符的位置加上1


可以如下选择文本


SendMessage(hwndEdit, EM_SETSEL, iStart, iEnd);


使用其他文本取代当前选择的文本


SendMessage(hwndEdit, EM_REPLACESEL, 0, (LPARAM)szString);




获得文本编辑器的行数


iCount = SendMessage(hwndEdit, EM_GETLINECOUNT, 0, 0);


获得从编辑器缓冲区的起点到这行的位移量


iOffset = SendMessage(hwndEdit, EM_LINEINDEX, iLine, 0 );


行的长度


iLength = SendMessage(hwndEdit, EM_LINELENGTH, iLine, 0);


复制某一行到缓冲区


iLength = SendMessage(hwndEdit, EM_GETLINE, iLine, (LPARAM)szBuffer);




9.6 列表框控件


支持单选或者多选 当有项目被选择会发送WM_COMMAND消息到其父窗口


被选中的项目会高亮显示


在单选列表框中,空格键选择项目。方向键可以移动光标和当前选择,可以滚动列表框的内容。 上下翻页也可以移动光标来滚动列表框,但不会移动项目,单击或者双击也可以选中项


多选列表框中,空格键用于切换光标所在项目的状态。方向键取消所有一切选定的项目,并移动光标和选中项。


9.6.1 列表框样式


WS_CHILD 子窗口控件


LBS_NOTIFY 使父窗口能够接受从列表框发来的WM_COMMAND信息


LBS_SORT 对项目进行排序


LBS_MULTIPLESEL 默认是单选 多选使用该样式


LBS_NOREDRAW 防止列表框自动更新


使用WM_SETREDRAW 消息


WS_BORDER 显示边框


WS_VSCROLL 显示垂直滚动条




在Windows头文件中定义了一个最标准的列表框样式


LBS_STANDARD  包含  (LBS_NOFITY | LBS_SORT | WS_VSCROLL | WS_BORDER)


WS_SIZEBOX 和 WS_CAPTION 允许用户调整列表框的尺寸,以及在父窗口的客户区移动它


GetSystemMetrics(SM_CXVSCROLL) 垂直滚动条的宽度


列表框的宽度 =  最长字符串的长度 + 滚动条的宽度。




9.6.2 向列表框添加字符


SendMessage 和索引来引用 最上方索引为0 


hwndList   iIndex


SendMessage传入文本字符串的时候 ,lParam参数是一个以空字符结尾的字符串的指针。


如果列表框用完了存储空间,SendMessage调用可能返回  LB_ERRSPACE值 ,如果其他错误则返回LB_ERR, 如果成功返回LB_OKAY


如果设定了LBS_SORT样式则 使用LB_ADDSTRING来添加字符串


SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)szString);


如果未使用LBS_SORT则使用


SendMessage(hwndList, LB_INSERTSTRING, iIndex, (LPARAM)szString);  //不排序




SendMessage(hwndList, LB_DELETESTRING, iIndex, 0 ) 删除列表框的指定位置处删除一字符串




SendMessage(hwndList, LB_RESETCONTENT, 0, 0); 删除所有项目




SendMessage(hwndList, WM_SETREDRAW, FALSE, 0 ); 关掉列表框重绘




SendMessage(hwndList, WM_SETREDRAW, TRUE, 0); 开启重绘




LBS_NOREDRAW样式的列表框最初开始会关闭重绘标志




9.6.3 项目的选取和提取




返回值LB_ERR




iCount = SendMessage(hwndList, LB_GETCOUNT, 0, 0 );  了解列表框有多少项目




对于单选


SendMessage(hwndList, LB_SETCURSEL, iIndex, 0);  设定选中项目


SendMessage(hwndList, LB_SETCURSEL, iIndex, -1);  取消选中项目




iIndex = SendMessage(hwndList, LB_SELECTSTRING, iIndex, (LPARAM)szSearchString); 根据起始字符选择


在收到来自列表框的WM_COMMAND消息时,可以使用LB_GETCURSEL获得当前选择的索引值


iIndex = SendMessage(hwndList, LB_GETCURSEL, 0, 0 );


如果未选择则返回  LB_ERR


iLength = SendMessage(hwndList, LB_GETTEXTLEN, iIndex, 0);  获得列表框中任何字符串的长度


并把改项目复制到文本缓冲区


iLength = SendMessage(hwndList, LB_GETTEXT, iIndex, (LPARAM)szBuffer);


可以利用GETTEXTLEN来为字符串存储预先分配空间。




对于多选框


不可使用  LB_SETCURSEL, LB_GETCURSEL 或者  LB_SELECTSTRING


应该使用LB_SETSEL


SendMessage(hwndList, LB_SETSEL, wParam, iIndex); 设定某个特定项目的选择状态。  wParam非0  选择并高亮显示, 如果是0. 取消选择。如果lParam则选择全部或者全部取消选择


iSelect = SendMessage(hwndList, LB_GETSEL, iIndex, 0); 判断指定项目是否被选择




9.6.4 接收来自列表框的消息


SetFocus(hwndList) 把焦点传给列表框






只有包含了LBS_NOFITY 列表框控件才会向父窗口发送LBN_SELCHANGE 和  LBN_DBLCLK.


9.6.5 简单的列表框程序





#include <windows.h>    #define ID_LIST		1#define ID_TEXT		2LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure.  int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,	PSTR szCmdLine, int iCmdShow){		static      TCHAR szAppName[] = TEXT("Environ");	HWND        hwnd;	MSG         msg;	WNDCLASS    wndClass;       //The window Class    	wndClass.style = CS_HREDRAW | CS_VREDRAW;	wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class.    	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_WINDOW + 1);//(HBRUSH)GetStockObject(WHITE_BRUSH);	wndClass.lpszMenuName = NULL;	wndClass.lpszClassName = szAppName;	//Register the Window Class to the Windows System.     	if (!RegisterClass(&wndClass))	{		MessageBox(NULL, TEXT("This program require Windows NT!"),			szAppName, MB_ICONERROR);		return 0;	}	//This function will generate an WM_CREATE message.    	hwnd = CreateWindow(szAppName,      //Window class name    		TEXT("Environment List Box"),      //Window caption    		WS_OVERLAPPEDWINDOW,            //Window Style    		CW_USEDEFAULT,                  //initial x position    		CW_USEDEFAULT,                  //initial y position    		CW_USEDEFAULT,                  //initial x size    		CW_USEDEFAULT,                  //initial y size    		NULL,                           //parent window handle    		NULL,                           //window menu handle    		hInstance,                      //program instance handle    		NULL);                          //creation parameters    	ShowWindow(hwnd, iCmdShow);	UpdateWindow(hwnd); //This function will generate a WM_PAINT message.    						/* The message loop for this program.						if received the WM_QUIT message, the function will return 0.*/	while (GetMessage(&msg, NULL, 0, 0))	{		TranslateMessage(&msg);		DispatchMessage(&msg);	}	return msg.wParam;}void FillListBox(HWND hwndList){	int		iLength;	TCHAR *	pVarEnv, * pVarBlock, *pVarBeg, *pVarEnd, *pVarName;	pVarEnv = GetEnvironmentStrings(); // Get pointer to environment block.	pVarBlock = pVarEnv;	while (*pVarBlock)	{		if (*pVarBlock != TEXT('=')) //Skip variable names beginning with '='		{			pVarBeg = pVarBlock;			//Beginning of variable name			while (*pVarBlock++ != TEXT('='));	//Scan until '='			pVarEnd = pVarBlock - 1;		//Points to '=' sign			iLength = pVarEnd - pVarBeg;	//Length of variable name			//Allocate memory for the variable name and terminating			//zero. Copy the variable name and append a zero.			pVarName = (TCHAR*)calloc(iLength + 1, sizeof(TCHAR));			CopyMemory(pVarName, pVarBeg, iLength * sizeof(TCHAR));			pVarName[iLength] = TEXT('\0');			//Put the variable name in the list box and free memory.			SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)pVarName);			free(pVarName);		}		while (*pVarBlock++ != TEXT('\0'));	//Scan until terminating zero	}	FreeEnvironmentStrings(pVarEnv);}//define the Window Procedure WndProc    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){	static HWND	hwndList, hwndText;	int			iIndex, iLength, cxChar, cyChar;	TCHAR	  *	pVarName, *pVarValue;	switch (message) //get the message    	{	case WM_CREATE:		cxChar = LOWORD(GetDialogBaseUnits());		cyChar = HIWORD(GetDialogBaseUnits());		//Create listbox and static text windows.		hwndList = CreateWindow(TEXT("listbox"), NULL,			WS_CHILD | WS_VISIBLE | LBS_STANDARD,			cxChar, cyChar * 3,			cxChar * 16 + GetSystemMetrics(SM_CXVSCROLL),			cyChar * 6,			hwnd, (HMENU)ID_LIST,			(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),			NULL);		hwndText = CreateWindow(TEXT("static"), NULL,			WS_CHILD | WS_VISIBLE | SS_LEFT,			cxChar, cyChar,			GetSystemMetrics(SM_CXSCREEN),			cyChar,			hwnd, (HMENU)ID_TEXT,			(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),			NULL);		FillListBox(hwndList);					return 0;	case WM_SETFOCUS:		SetFocus(hwndList);		return 0;	case WM_COMMAND:		if (LOWORD(wParam) == ID_LIST && HIWORD(wParam) == LBN_SELCHANGE)		{			//Get current selection.			iIndex = SendMessage(hwndList, LB_GETCURSEL, 0, 0);			iLength = SendMessage(hwndList, LB_GETTEXTLEN, iIndex, 0) + 1;			pVarName = (TCHAR*)calloc(iLength, sizeof(TCHAR));			SendMessage(hwndList, LB_GETTEXT, iIndex, (LPARAM)pVarName);			//Get environment string.			iLength = GetEnvironmentVariable(pVarName, NULL, 0);			pVarValue = (TCHAR*)calloc(iLength, sizeof(TCHAR));			GetEnvironmentVariable(pVarName, pVarValue, iLength);			//Show it in window			SetWindowText(hwndText, pVarValue);			free(pVarName);			free(pVarValue);		}		return 0;	case WM_DESTROY:		PostQuitMessage(0);		return 0;	}	return  DefWindowProc(hwnd, message, wParam, lParam);}
运行结果







9.6.6 列出文件


SendMessage(hwndList, LB_DIR, iAttr, (LPARAM) szFileSpec);


将文件目录列表写入列表框中,包括子目录和有效的磁盘驱动器。




lParam 是一个指向文件限定字符(*.*)的指针。该文件限定不影响列表框包含的子目录


实例代码





		hwndListDir = CreateWindow(TEXT("listbox"), NULL,			WS_CHILD | WS_VISIBLE | LBS_STANDARD ,			cxChar, cyChar * 10,			cxChar * 16 + GetSystemMetrics(SM_CXVSCROLL),			cyChar * 6,			hwnd, (HMENU)ID_LIST,			(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),			NULL);



SendMessage(hwndListDir, LB_DIR, DDL_READWRITE | DDL_DRIVES | DDL_DIRECTORY,


(LPARAM)(TEXT("*.*")));



9.6.7 Windows的HEAD程序



#include <windows.h>    #define ID_LIST		1#define ID_TEXT		2#define MAXREAD		8192#define DIRATTR		(DDL_READWRITE | DDL_READONLY | DDL_HIDDEN | DDL_SYSTEM | \					DDL_DIRECTORY | DDL_ARCHIVE | DDL_DRIVES)#define DTFLAGS		(DT_WORDBREAK | DT_EXPANDTABS | DT_NOCLIP | DT_NOPREFIX)LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure.  LRESULT CALLBACK ListProc(HWND, UINT, WPARAM, LPARAM);WNDPROC OldList;int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,	PSTR szCmdLine, int iCmdShow){		static      TCHAR szAppName[] = TEXT("head");	HWND        hwnd;	MSG         msg;	WNDCLASS    wndClass;       //The window Class    	wndClass.style = CS_HREDRAW | CS_VREDRAW;	wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class.    	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_BTNFACE + 1);//(HBRUSH)GetStockObject(WHITE_BRUSH);	wndClass.lpszMenuName = NULL;	wndClass.lpszClassName = szAppName;	//Register the Window Class to the Windows System.     	if (!RegisterClass(&wndClass))	{		MessageBox(NULL, TEXT("This program require Windows NT!"),			szAppName, MB_ICONERROR);		return 0;	}	//This function will generate an WM_CREATE message.    	hwnd = CreateWindow(szAppName,      //Window class name    		TEXT("head"),      //Window caption    		WS_OVERLAPPEDWINDOW,            //Window Style    		CW_USEDEFAULT,                  //initial x position    		CW_USEDEFAULT,                  //initial y position    		CW_USEDEFAULT,                  //initial x size    		CW_USEDEFAULT,                  //initial y size    		NULL,                           //parent window handle    		NULL,                           //window menu handle    		hInstance,                      //program instance handle    		NULL);                          //creation parameters    	ShowWindow(hwnd, iCmdShow);	UpdateWindow(hwnd); //This function will generate a WM_PAINT message.    						/* The message loop for this program.						if received the WM_QUIT message, the function will return 0.*/	while (GetMessage(&msg, NULL, 0, 0))	{		TranslateMessage(&msg);		DispatchMessage(&msg);	}	return msg.wParam;}//define the Window Procedure WndProc    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){	static BOOL		bValidFile;	static BYTE		buffer[MAXREAD];	static HWND		hwndList, hwndText;	static RECT		rect;	static TCHAR	szFile[MAX_PATH + 1];	HANDLE			hFile;	HDC				hdc;	int				i, cxChar, cyChar;	PAINTSTRUCT		ps;	TCHAR			szBuffer[MAX_PATH + 1];	switch (message) //get the message    	{	case WM_CREATE:		cxChar = LOWORD(GetDialogBaseUnits());		cyChar = HIWORD(GetDialogBaseUnits());		rect.left = 20 * cxChar;		rect.top = 3 * cyChar;		//Create listbox and static text windows.		hwndList = CreateWindow(TEXT("listbox"), NULL,			WS_CHILDWINDOW | WS_VISIBLE | LBS_STANDARD,			cxChar, cyChar * 3,			cxChar * 13 + GetSystemMetrics(SM_CXVSCROLL),			cyChar * 10,			hwnd, (HMENU)ID_LIST,			(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),			NULL);		GetCurrentDirectory(MAX_PATH + 1, szBuffer);		hwndText = CreateWindow(TEXT("static"), szBuffer,			WS_CHILDWINDOW | WS_VISIBLE | SS_LEFT,			cxChar, cyChar,			cxChar * MAX_PATH,			cyChar,			hwnd, (HMENU)ID_TEXT,			(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),			NULL);				OldList = (WNDPROC)SetWindowLong(hwndList, GWL_WNDPROC, (LPARAM)ListProc);		SendMessage(hwndList, LB_DIR, DIRATTR, (LPARAM)TEXT("*.*"));				return 0;	case WM_SIZE:		rect.right	= LOWORD(lParam);		rect.bottom = HIWORD(lParam);		return 0;	case WM_SETFOCUS:		SetFocus(hwndList);		return 0;	case WM_COMMAND:		if (LOWORD(wParam) == ID_LIST && HIWORD(wParam) == LBN_DBLCLK)		{			i = SendMessage(hwndList, LB_GETCURSEL, 0, 0);			if (i == LB_ERR)				break;			SendMessage(hwndList, LB_GETTEXT, i, (LPARAM)szBuffer);			if (INVALID_HANDLE_VALUE != (hFile = CreateFile(szBuffer,				GENERIC_READ, FILE_SHARE_READ, NULL,				OPEN_EXISTING, 0, NULL)))			{				CloseHandle(hFile);				bValidFile = TRUE;				lstrcpy(szFile, szBuffer);				GetCurrentDirectory(MAX_PATH + 1, szBuffer);				if (szBuffer[lstrlen(szBuffer) - 1] != TEXT('\\'))					lstrcat(szBuffer, TEXT("\\"));				SetWindowText(hwndText, lstrcat(szBuffer, szFile));			}			else			{				bValidFile = FALSE;				szBuffer[lstrlen(szBuffer) - 1] = TEXT('\0');				//if setting the directory doesn't work, maybe it's				//a drive change, so try that.				if (!SetCurrentDirectory(szBuffer + 1))				{					szBuffer[3] = TEXT(':');					szBuffer[4] = TEXT('\0');					SetCurrentDirectory(szBuffer + 2);				}				//Get the new directory name and fill the list box.				GetCurrentDirectory(MAX_PATH + 1, szBuffer);				SetWindowText(hwndText, szBuffer);				SendMessage(hwndList, LB_RESETCONTENT, 0, 0);				SendMessage(hwndList, LB_DIR, DIRATTR,					(LPARAM)TEXT("*.*"));			}			InvalidateRect(hwnd, NULL, TRUE);		}		return 0;	case WM_PAINT:		if (!bValidFile)			break;		if (INVALID_HANDLE_VALUE != (hFile = CreateFile(szFile,			GENERIC_READ, FILE_SHARE_READ, NULL,			OPEN_EXISTING, 0, NULL)))		{			bValidFile = FALSE;		}		ReadFile(hFile, buffer, MAXREAD, (LPDWORD)&i, NULL);		CloseHandle(hFile);		//i now equals the number of bytes in buffer.		//Commence getting a device context for displaying text.		hdc = BeginPaint(hwnd, &ps);		SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));		SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));		SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));		//Assume the file is ASCII		DrawTextA(hdc, (LPCSTR)buffer, i, &rect, DTFLAGS);		EndPaint(hwnd, &ps);		return 0;	case WM_DESTROY:		PostQuitMessage(0);		return 0;	}	return  DefWindowProc(hwnd, message, wParam, lParam);}LRESULT CALLBACK ListProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){	if(message == WM_KEYDOWN && wParam == VK_RETURN)		SendMessage(GetParent(hwnd), WM_COMMAND, MAKELONG(1, LBN_DBLCLK), (LPARAM)hwnd);	return CallWindowProc(OldList, hwnd, message, wParam, lParam);}






发现原书上的代码中使用DrawTextA当文本长度高无法翻页滚动流量,而且不支持UNICODE。因此对此进行了改进。使用了文本框控件和ASCII转UNICODE函数



				//We convert the encode from the ASCII to UNICODE.				MultiByteToWideChar(CP_ACP, 0, (LPCCH)buffer, MAXREAD, wbuffer, MAXREAD);

另外在读取文件到buffer之前要情况buffer内容


memset(buffer, 0, MAXREAD * sizeof(BYTE));



代码如下



#include <windows.h>    #define ID_LIST		1#define ID_TEXT		2#define ID_EDIT		3#define MAXREAD		8192#define DIRATTR		(DDL_READWRITE | DDL_READONLY | DDL_HIDDEN | DDL_SYSTEM | \					DDL_DIRECTORY | DDL_ARCHIVE | DDL_DRIVES)#define DTFLAGS		(DT_WORDBREAK | DT_EXPANDTABS | DT_NOCLIP | DT_NOPREFIX)LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure.  LRESULT CALLBACK ListProc(HWND, UINT, WPARAM, LPARAM);WNDPROC OldList;int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,	PSTR szCmdLine, int iCmdShow){		static      TCHAR szAppName[] = TEXT("head");	HWND        hwnd;	MSG         msg;	WNDCLASS    wndClass;       //The window Class    	wndClass.style = CS_HREDRAW | CS_VREDRAW;	wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class.    	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_BTNFACE + 1);//(HBRUSH)GetStockObject(WHITE_BRUSH);	wndClass.lpszMenuName = NULL;	wndClass.lpszClassName = szAppName;	//Register the Window Class to the Windows System.     	if (!RegisterClass(&wndClass))	{		MessageBox(NULL, TEXT("This program require Windows NT!"),			szAppName, MB_ICONERROR);		return 0;	}	//This function will generate an WM_CREATE message.    	hwnd = CreateWindow(szAppName,      //Window class name    		TEXT("head"),      //Window caption    		WS_OVERLAPPEDWINDOW,            //Window Style    		CW_USEDEFAULT,                  //initial x position    		CW_USEDEFAULT,                  //initial y position    		CW_USEDEFAULT,                  //initial x size    		CW_USEDEFAULT,                  //initial y size    		NULL,                           //parent window handle    		NULL,                           //window menu handle    		hInstance,                      //program instance handle    		NULL);                          //creation parameters    	ShowWindow(hwnd, iCmdShow);	UpdateWindow(hwnd); //This function will generate a WM_PAINT message.    						/* The message loop for this program.						if received the WM_QUIT message, the function will return 0.*/	while (GetMessage(&msg, NULL, 0, 0))	{		TranslateMessage(&msg);		DispatchMessage(&msg);	}	return msg.wParam;}BOOL LoadFile(LPTSTR szFile, BOOL& bValidFile, BYTE * buffer){	HANDLE	hFile;	int		iLength;	if (!bValidFile)		return FALSE;	memset(buffer, 0, MAXREAD * sizeof(BYTE));	if (INVALID_HANDLE_VALUE != (hFile = CreateFile(szFile,		GENERIC_READ, FILE_SHARE_READ, NULL,		OPEN_EXISTING, 0, NULL)))	{		bValidFile = FALSE;	}	ReadFile(hFile, buffer, MAXREAD, (LPDWORD)&iLength, NULL);	CloseHandle(hFile);	return TRUE;}//define the Window Procedure WndProc    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){	static BOOL		bValidFile;	static BYTE		buffer[MAXREAD];	static WCHAR	wbuffer[MAXREAD];	static HWND		hwndList, hwndText, hwndEdit;	static RECT		rect;	static TCHAR	szFile[MAX_PATH + 1];	HANDLE			hFile;	int				i, cxChar, cyChar;	TCHAR			szBuffer[MAX_PATH + 1];	switch (message) //get the message    	{	case WM_CREATE:		cxChar = LOWORD(GetDialogBaseUnits());		cyChar = HIWORD(GetDialogBaseUnits());		rect.left = 20 * cxChar;		rect.top = 3 * cyChar;		//Create listbox and static text windows.		hwndList = CreateWindow(TEXT("listbox"), NULL,			WS_CHILDWINDOW | WS_VISIBLE | LBS_STANDARD,			cxChar, cyChar * 3,			cxChar * 13 + GetSystemMetrics(SM_CXVSCROLL),			cyChar * 10,			hwnd, (HMENU)ID_LIST,			(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),			NULL);		GetCurrentDirectory(MAX_PATH + 1, szBuffer);		hwndText = CreateWindow(TEXT("static"), szBuffer,			WS_CHILDWINDOW | WS_VISIBLE | SS_LEFT,			cxChar, cyChar,			cxChar * MAX_PATH,			cyChar,			hwnd, (HMENU)ID_TEXT,			(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),			NULL);		hwndEdit = CreateWindow(TEXT("edit"), NULL,			WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL |			WS_BORDER | ES_LEFT | ES_MULTILINE |			ES_AUTOHSCROLL | ES_AUTOVSCROLL,			0, 0, 0, 0,			hwnd, (HMENU)ID_EDIT,			((LPCREATESTRUCT)lParam)->hInstance, NULL);				OldList = (WNDPROC)SetWindowLong(hwndList, GWL_WNDPROC, (LPARAM)ListProc);		SendMessage(hwndList, LB_DIR, DIRATTR, (LPARAM)TEXT("*.*"));				return 0;	case WM_SIZE:		rect.right	= LOWORD(lParam);		rect.bottom = HIWORD(lParam);		MoveWindow(hwndEdit, rect.left, rect.top, 			rect.right - rect.left, 			rect.bottom - rect.top, TRUE);		return 0;	case WM_SETFOCUS:		SetFocus(hwndList);		return 0;	case WM_COMMAND:		if (LOWORD(wParam) == ID_LIST && HIWORD(wParam) == LBN_DBLCLK)		{			i = SendMessage(hwndList, LB_GETCURSEL, 0, 0);			if (i == LB_ERR)				break;			SendMessage(hwndList, LB_GETTEXT, i, (LPARAM)szBuffer);			if (INVALID_HANDLE_VALUE != (hFile = CreateFile(szBuffer,				GENERIC_READ, FILE_SHARE_READ, NULL,				OPEN_EXISTING, 0, NULL)))			{				CloseHandle(hFile);				bValidFile = TRUE;				lstrcpy(szFile, szBuffer);				GetCurrentDirectory(MAX_PATH + 1, szBuffer);				if (szBuffer[lstrlen(szBuffer) - 1] != TEXT('\\'))					lstrcat(szBuffer, TEXT("\\"));				SetWindowText(hwndText, lstrcat(szBuffer, szFile));			}			else			{				bValidFile = FALSE;				szBuffer[lstrlen(szBuffer) - 1] = TEXT('\0');				//if setting the directory doesn't work, maybe it's				//a drive change, so try that.				if (!SetCurrentDirectory(szBuffer + 1))				{					szBuffer[3] = TEXT(':');					szBuffer[4] = TEXT('\0');					SetCurrentDirectory(szBuffer + 2);				}				//Get the new directory name and fill the list box.				GetCurrentDirectory(MAX_PATH + 1, szBuffer);				SetWindowText(hwndText, szBuffer);				SendMessage(hwndList, LB_RESETCONTENT, 0, 0);				SendMessage(hwndList, LB_DIR, DIRATTR,					(LPARAM)TEXT("*.*"));			}			if (LoadFile(szFile, bValidFile, buffer))			{				//We convert the encode from the ASCII to UNICODE.				MultiByteToWideChar(CP_ACP, 0, (LPCCH)buffer, MAXREAD, wbuffer, MAXREAD);				SetWindowText(hwndEdit, (LPCTSTR)wbuffer);			}		}		return 0;	case WM_DESTROY:		PostQuitMessage(0);		return 0;	}	return  DefWindowProc(hwnd, message, wParam, lParam);}LRESULT CALLBACK ListProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){	if(message == WM_KEYDOWN && wParam == VK_RETURN)		SendMessage(GetParent(hwnd), WM_COMMAND, MAKELONG(1, LBN_DBLCLK), (LPARAM)hwnd);	return CallWindowProc(OldList, hwnd, message, wParam, lParam);}














不过发现还有一个问题,就是纯文本的编码可能多种多样。这里既是支持了转换为UNICODE显示,有些本身是UTF8 或者UNICODE编码的文本就会乱码。这设计到很多编码的转换了,将在以后改进。


上一篇:Vim入门基础
下一篇:《Windows程序设计》读书笔八 计时器

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2025年03月30日 06时58分25秒