Windows程序设计 学习笔记 第九章 子窗口控件

目录:


文章目录


注:
按钮通知码含义未填
父窗口给按钮的消息表含义未填完
六.3.3 LB_DIR待补充

一,按钮类

1.创建子窗口
hwndButton = CreateWindow(
				TEXT("button"),TextOfBtn,WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
				cxChar,cyChar*(1+2*i),20*cxChar,7*cyChar/4,hwnd,(HMENU)i,
				((LPCREATESTRUCT)lParam)->hInstance,NULL
				);
  • 窗口类名为 “button”
  • 子窗口的窗口样式必须有 WS_CHILD|WS_VISIBLE。
  • 按钮样式(窗口样式)十种
  • 每个子窗口的 ID 参数应是唯一的,它的位置原本是用于指定窗口菜单的,所以必须转换成 HMENU 类型。
  • 按钮窗口过程在Windows 中维护所有的按钮和处理重绘任务。(例外是 BS_OWNERDRAW 样式的按钮需要自己绘制)

拓展1——获取对话框字符尺寸的方法

可使用 GetDialogBaseUnits 函数获取字符的默认宽度和高度,对话框使用这个函数获取字符尺寸。
该函数返回一个32位值,低位字是子窗口宽度,高位字是子窗口高度。
比起 GetTextMetrics 更易于使用,更利于保持对话框控件的更多的一致性。


拓展2——获取实例句柄的方法

方法①:

((LPCREATESTRUCT)lParam)->hInstance

即,WM_CREATE 消息的 lParan 参数是一个指向 CREATESTRUCT 结构类型的指针,hInstance 则是该结构的一个成员。
方法②:

GetWindowLong(hwnd,GWL_HINSTANCE);

方法③:
定义一个全局变量 hInst,并在 WInMain 函数中赋值。


2.子窗口传递消息给父窗口

在用鼠标单击一个按钮时,子窗口控件发送 WM_COMMAND 消息给其父窗口。该消息的参数如下:

参数含义
LOWORD子窗口ID
HIWORD通知码
lParam子窗口句柄

通知吗进一步给出每条消息的意思。

按钮通知码标识符含义
BN_CLICKED0点击
BN_PAINT1(过时,用于BS_USERBUTTON)
BN_HILITE 或 BN_PUSHED2(过时,用于BS_USERBUTTON)
BN_UNHILITE 或 BN_UNPUSHED3(过时,用于BS_USERBUTTON)
BN_DISABLE4(过时,用于BS_USERBUTTON)
BN_DOUBLECLIECKED 或 BN_DBLCLK5双击(只用于 BS_RADIOBUTTON,BS_AUTORADIOBUTTON 和 BS_OWNERDRAW,或 包含BS_NOTIFY 的其他按钮)
BN_SETFOCUS6(按钮样式包含 BS_NOTIFY 才会发送)
BN_KILLFOCUS7(按钮样式包含 BS_NOTIFY 才会发送)

1~4用于过时的按钮样式 BS_USERBUTTON(它已被 BS_OWNERDRAW 和另外一套通知机制取代)。

鼠标单击按钮时,按钮文本的周围会出现一圈虚线,这表明按钮有输入焦点,所有键盘消息会送到这个子窗口按钮控件,而不是主窗口。按钮控件一旦获得输入焦点,便会忽略除空格键外所有按键操作,此时空格键有和单击按钮相同的效果。

3.父窗口传递信息给子窗口

WINUSER.H 中定义了8个专用于按钮的消息,以 BM 开头

按钮消息含义
BM_GETCHECK0x00F0获取复选框和单选框的选择状态
BM_SETCHECK0x00F1设置复选框和单选框的选择状态
BM_GETSTATE0x00F2反映窗口的状态是正常还是被单击了
BM_SETSTATE0x00F3设置窗口的状态是正常还是被单击了
BM_SETSTYLE0x00F4允许在创建按钮后改变按钮样式
BM_CLICK0x00F5
BM_GETIMAGE0x00F6
BM_SETIMAGE0x00F7

拓展3 窗口句柄与ID 的相互获取
① 已知窗口句柄 获取 ID
id = GetWindowLong(hwndChild,GWL_ID);

id = GetWindowWord(hwndChild,GWL_ID);

id = GetDlgCtrlID(hwndChild); //是一个通用的函数,并不只是对话框
②已知子窗口ID 获取 子窗口句柄
hwndChild = GetDlgItem(hwndParent,id);

4. 按钮(按键按钮)

按键按钮
BS_PUSHBUTTON 和 BS_DEFPUSHBUTTON

在被用作子窗口控件时,两者基本相同,只是 BS_DEFPUSHBUTTON 会有较重的轮廓;在设计对话框时完全不同。

  • 大小规格(大都是如此):
    按键按钮的最佳视觉高度是字符高度的 7/4 。
    宽度是文本的宽度+两个字符宽度。

  • 消息:
    单击按钮(在释放鼠标)时,按钮会发送通知码为 BN_CLICKED 的 WM_COMMAND 消息到父窗口。

  • 状态:
    通过给Windows 发送一个 BM_SETSTATE 消息,可以模拟按键按钮的状态变化,使之看上去像被按住了一样

    SendMessage(hwndButton,BM_SETSTATE,1,0);
    

    下面这个会让按钮回到正常状态

    SendMessage(hwndButton,BM_SETSTATE,0,0);
    

    还可以通过发送 BM_GETSTATE 消息获取当前按钮的状态,如果是按下的,返回TRUE;没有被按下则返回 FALSE。

按键按钮没有保存开关信息,所以不用 BM_SETCHECK 和BM_GETCHECK 。

5.复选框

带文本的正方形框,文本通常出现在右侧(窗口样式包含 BS_LEFTTEXT 会使文本出现在左侧,还可组合使用 BS_RIGHT 使左侧文本右对齐),。

最常见两类样式:BS_CHECKBOX 和 BX_AUTOCHECKBOX

BS_CHECKBOX

使用 BS_CHECKBOX 时必须自己给控件发送 BM_SETCHECK 消息来设置其选中标记,wParam 为1 则选中,为0则清除选中。还可通过BM_GETCHECK 消息来获取当前选中状态。

切换选中标记代码:

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

复选框被选中,则 iCheck 的值为 TRUE 或 非零,否则为 FALSE 或 0 。

BS_3STATE 和 BS_AUTO3STATE

可以显示第三种状态——灰色,当向控件发送 BM_SETCHECK 消息时 wParan 参数为2 时。

6.单选按钮(单选框)

窗口样式有 BS_RADIOBUTTON 和 BS_AUTORADIOBUTTON,后者只用于对话框

单选框一般分组使用,在收到WM_COMMAND 消息后,可向它发送一条wParam =1 的 BM_SETCHECK 消息来显示其选中标记。

SendMessage(hwndButton,BM_SETCHECK,1,0);

对于其他同一组的所有单选框,则取消其选中标记(wParam=0 的 BM_SETCHECK 消息)

SendMessage(hwndButton,BM_SETCHECK,0,0);
7. 组合框

BS_GROUPBOX
就是一个矩形外框…

8. 改变,获取按钮文本(窗口文本)

改变按钮中的文本(窗口文本)

SetWindowText(hwnd,pszString);

获得窗口的当前文本

iLength = GetWindowText(hwnd,pszBuffer,iMaxLength);

可先作如下准备,获取文本长度

iLength = GetWindowTextLength(hwnd);
9.按钮的可见与启用
9.1 可见

创建子窗口时没有 包含窗口样式 WS_VISIBLE 将不会显示子窗口,除非 调用 ShowWindow()

ShowWindow(hwndChild,SW_SHOWNORMAL);

还可调用这个函数 隐藏窗口

ShowWindow(hwndChild,SW_HIDE);

还可用IsWindowVisible()来判断窗口是否可见

IsWindowVisible(hwndChild);
9.2 启用

默认情况下窗口处于启用状态

可用下面语句禁用子窗口,禁用的窗口无法响应鼠标和键盘输入

EnableWindow(hwndChild,FALSE);

会使按钮的文本变成灰色。

重新启用子窗口:

EnableWindow(hwndChild,TRUE);

还可用IsWindowEnabled() 判断子窗口是否已被启用:

IsWindowEnabled(hwndChild);
10.按钮和输入焦点

Windows 输入焦点切换时:

窗口窗口获得的消息消息的 wParam 参数
(先)失去输入焦点的窗口(如父窗口)WM_KILLFOCUS将要获得输入焦点的窗口的句柄
(后)要接收输入焦点的窗口(如子窗口控件)WM_SETFOCUS失去输入焦点的窗口句柄

两个wParam 参数都可能是 NULL ,表示没有窗口具有输入焦点或没有窗口正在接收输入焦点。

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

case WM_KILLFOCUS:
	 for(i=0;i<NUM;i++)//NUM 是子窗口的数量
	 	if(hwndChild[i] == (HWND)wParam)
	 	{
	 		SetFocus(hwnd);
	 		break;
	 	}
	 return 0;

↓ 这个可以检测所有子窗口

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

这两种方法的缺点是无法让按钮响应空格键,或者用 Tab键 从一个按钮转移输入焦点到另一个按钮,可通过 “窗口子类” 的技术来实现它。

二,控件和颜色

按钮的背景是灰色的…难看…

1.系统颜色

Windows 有29 种系统颜色来支持各部分的显示。
可用 GetSysColor 和 SetSysColors 获取并设置这些颜色,使用SetSysColors 设置的系统颜色仅仅影响到当前的窗口会话。

GetSysColor 和 SetSysColors|注册表值或WIN.INI标识符
在这里插入图片描述

2.按钮的颜色(其实是改变其他颜色)

COLOR_BTNFACE 用于 按键按钮的主表面颜色和其他按钮的背景颜色(也是对话框和消息框使用的系统颜色)

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

COLOR_BTNTEXT 按键按钮的文本颜色

COLOR_WINDOWTEXT 其他其他控件的文本颜色

所以,避免按钮颜色与客户区表面颜色冲突的途径就是将这些系统颜色设置成背景颜色。

对于客户区背景:

wndClass.hbrBackground = (HBRUSH) (COLOR_BTNFACE+1); //为了防止出现NULL值
  • Windows 知道,在WNDCLASS结构中 hbrBackgroung 的值很低时,实际上指的是系统颜色,而不是实际句柄,+1是为了防止出现NULL。
  • 若程序运行时系统颜色发生改变,那么客户区表面会变为无效,Windows 讲使用新的 COLOR_BTNFACE 值。

对于文本背景及文本颜色:

SetBkColor(hdc,GetSysColor(COLOR_BTNFACE));
SetTextColor(hdc,GetSysColor(COLOR_WINDOWTEXT));

若程序运行时系统颜色被改变:

case WM_SYSCOLORCHANGE:
	InvalidateRect(hwnd,NULL,TRUE);
	break;
3.WM_CTLCOLORBTN 消息

当子窗口即将重绘其客户区时,按钮控件(只有按键按钮和自绘按钮会发送)会把这个消息发送给其父窗口的窗口过程。可以利用这个改变子窗口的背景颜色(只有自绘按钮会对该消息作出反应)。

WM_CTLCOLORBTN 消息参数

wParam 是按钮的设备环境句柄
lParam 是按钮的窗口句柄

可以在处理该消息时:

  • 使用SetColor 设置文本颜色
  • 使用 SetBkColor 设置文本的背景颜色
  • 返回子窗口的画刷句柄(子窗口用这个画刷着色背景),不需要时销毁画刷。

!!!问题:
只有按键按钮和自绘按钮会发送该消息
只有自绘按钮会对该消息作出反应(这又是没必要的)

4.自绘按钮
#include<windows.h>

#define ID_SMALLER 1
#define ID_LARGER  2
#define BTN_WIDTH  (8*cxChar)
#define BTN_HEIGHT  (4*cyChar)

HINSTANCE hInst;

LRESULT CALLBACK WinProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE PreInstance,PSTR szCmdLine,int iCmdShow)
{
	MSG msg;
	TCHAR *szAppName=TEXT("MyApp");
	HWND hwnd;
	WNDCLASS wndclass;
	hInst=hInstance;

	wndclass.style=CS_VREDRAW|CS_HREDRAW;
	wndclass.lpfnWndProc=WinProc;
	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;
	
	
	RegisterClass(&wndclass);
	
	//hwnd=CreateWindowEx()?
	
	hwnd=CreateWindow(szAppName,TEXT("Caption"),WS_OVERLAPPEDWINDOW,
					CW_USEDEFAULT,CW_USEDEFAULT,600,400,
					NULL,NULL,hInstance,NULL
					);
	
	ShowWindow(hwnd,iCmdShow);
	
	while(GetMessage(&msg,NULL,0,0)){
		TranslateMessage(&msg);
		DispatchMessage(&msg);
		
	}
	return msg.wParam;
}

//Draw a triangle
void Triangle(HDC hdc,POINT *pt)
{
	SelectObject(hdc,GetStockObject(BLACK_BRUSH));
	Polygon(hdc,pt,3);
	SelectObject(hdc,GetStockObject(WHITE_BRUSH));
}


LRESULT CALLBACK WinProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;

	POINT pt[3];
	static HWND hwndSmaller,hwndLarger,hwndPushBtn;
	LPDRAWITEMSTRUCT pdis;
	static RECT rc;
	
	static int cxChar,cyChar,cxClient,cyClient;
	int cx,cy;
	static HBRUSH hBrush;
	switch(message){
		case WM_CREATE:
			cxChar=LOWORD(GetDialogBaseUnits());
			cyChar=HIWORD(GetDialogBaseUnits());

			hwndSmaller=CreateWindow(TEXT("button"),TEXT(""),WS_CHILD|WS_VISIBLE|BS_OWNERDRAW,
				0,0,BTN_WIDTH,BTN_HEIGHT,hwnd,(HMENU)ID_SMALLER,hInst,NULL);
			hwndLarger=CreateWindow(TEXT("button"),TEXT(""),WS_CHILD|WS_VISIBLE|BS_OWNERDRAW,
				0,0,BTN_WIDTH,BTN_HEIGHT,hwnd,(HMENU)ID_LARGER,hInst,NULL);
			hwndPushBtn=CreateWindow(TEXT("button"),TEXT("Push"),WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
				0,0,6*cxChar,7/4*cyChar,hwnd,(HMENU)3,hInst,NULL);

			break;
		case WM_SIZE:
			cxClient=LOWORD(lParam);
			cyClient=HIWORD(lParam);

			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);
			MoveWindow(hwndPushBtn,20,20,6*cxChar,7*cyChar/4,TRUE);
			break;
		case WM_COMMAND:

			GetWindowRect(hwnd,&rc);

			switch(wParam)
			{
			case ID_SMALLER:
				rc.left +=cxClient/20;
				rc.right-=cxClient/20;
				rc.bottom-=cyClient/20;
				rc.top+=cyClient/20;
				break;
			case ID_LARGER:
				rc.left -=cxClient/20;
				rc.right+=cxClient/20;
				rc.bottom+=cyClient/20;
				rc.top-=cyClient/20;
				break;
			}
			MoveWindow(hwnd,rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top,TRUE);

			break;
		case WM_DRAWITEM:
			pdis=(LPDRAWITEMSTRUCT)lParam;
			hBrush=CreateSolidBrush(RGB(0,0,255));
			FillRect(pdis->hDC,&pdis->rcItem,(HBRUSH)GetStockObject(WHITE_BRUSH));
			FrameRect(pdis->hDC,&pdis->rcItem,hBrush);
			
			cx=pdis->rcItem.right-pdis->rcItem.left;
			cy=pdis->rcItem.bottom-pdis->rcItem.top;


			//点击与不点击状态绘制
			if(pdis->itemState&ODS_SELECTED)	
				switch(pdis->CtlID)
			{
			case ID_SMALLER:
				pt[0].x=3*cx/8;  pt[0].y=2*cy/8;
				pt[1].x=5*cx/8;  pt[1].y=2*cy/8;
				pt[2].x=4*cx/8;  pt[2].y=4*cy/8;
				Triangle(pdis->hDC,pt);

				pt[0].x=6*cx/8;  pt[0].y=3*cy/8;
				pt[1].x=6*cx/8;  pt[1].y=5*cy/8;
				pt[2].x=4*cx/8;  pt[2].y=4*cy/8;
				Triangle(pdis->hDC,pt);

				pt[0].x=5*cx/8;  pt[0].y=6*cy/8;
				pt[1].x=3*cx/8;  pt[1].y=6*cy/8;
				pt[2].x=4*cx/8;  pt[2].y=4*cy/8;
				Triangle(pdis->hDC,pt);

				pt[0].x=2*cx/8;  pt[0].y=5*cy/8;
				pt[1].x=2*cx/8;  pt[1].y=3*cy/8;
				pt[2].x=4*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=2*cy/8;
				pt[1].x=3*cx/8;  pt[1].y=2*cy/8;
				pt[2].x=4*cx/8;  pt[2].y=0*cy/8;
				Triangle(pdis->hDC,pt);

				pt[0].x=6*cx/8;  pt[0].y=5*cy/8;
				pt[1].x=6*cx/8;  pt[1].y=3*cy/8;
				pt[2].x=8*cx/8;  pt[2].y=4*cy/8;
				Triangle(pdis->hDC,pt);

				pt[0].x=3*cx/8;  pt[0].y=6*cy/8;
				pt[1].x=5*cx/8;  pt[1].y=6*cy/8;
				pt[2].x=4*cx/8;  pt[2].y=8*cy/8;
				Triangle(pdis->hDC,pt);

				pt[0].x=2*cx/8;  pt[0].y=3*cy/8;
				pt[1].x=2*cx/8;  pt[1].y=5*cy/8;
				pt[2].x=0*cx/8;  pt[2].y=4*cy/8;
				Triangle(pdis->hDC,pt);
			}
			
			else
				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;
			}
			if(pdis->itemState&ODS_FOCUS)//获得焦点 绘制虚线
			{
				pdis->rcItem.left += cx/16;
				pdis->rcItem.top += cy/16;
				pdis->rcItem.right -= cx/16;
				pdis->rcItem.bottom -= cx/16;

				DrawFocusRect(pdis->hDC,&pdis->rcItem);
			}

				
			break;
		case WM_KILLFOCUS:
			/*if(GetParent((HWND)wParam)==hwnd)
				SetFocus(hwnd);*/
			break;
		
		case WM_DESTROY:
			DeleteObject(hBrush);
			PostQuitMessage(0);
			break;
		default:
			return DefWindowProc(hwnd,message,wParam,lParam);	
		
	}
	return 0;
	
}

效果:
在这里插入图片描述
自绘按钮——包含 BS_OWNDRAW 的按钮

WM_DRAWITEM

对于自绘按钮,在需要重绘时会向父窗口发送WM_DRAWITEM 消息。
会在以下情况发生重绘:

  • 新建按钮时
  • 按钮被按下或释放时
  • 按钮得到或失去输入焦点时
  • 其他

消息参数:

  • lParam 是一个指向 DRAWITEMSTRUCT 类型的结构
    这个结构中与按钮有重要关系的有
    • hDC(按钮设备环境)
    • reItem(RECT结构,提供按钮尺寸)
    • CtlID(控件窗口ID)
    • itemState(按钮是否被按下或有输入焦点)
      可用 ODS_SELECTED 测试这位值是否是被按下状态

使用自绘按钮的忠告:

  • 必须保持 DRAWITEMSTRUCT 中 hDC 的状态,即任何被选入该设备环境的 GDI 对象必须设置回原有的不被选中的状态
  • 不能在按钮的区域外绘制任何图形

三,静态类

窗口类名为 “static” 的子窗口控件,它们不接受鼠标或键盘输入,也不会向父窗口发送 WM_COMMAND 消息。

当你在一个静态子窗口上移动或单击鼠标时,子窗口回俘获 WM_NCHITTEST 消息,并向Windows 返回 HTTRANSPARENT值,这会导致Windows向其底层窗口发送相同的 WM_NCHITTEST 消息,父窗口通常将该消息传给DefWindowsProc 处理,在那里它会被转换为客户区鼠标消息

1.简单样式(矩形和框)

前6个静态窗口样式只是简单的在子窗口客户区内画一个矩形或框架

填充的矩形不填充的矩形边框
SS_BLACKRECTSS_BALCKFRAME
SS_GRAYRECTSS_GRAYFRAME
SS_WHITERECTSS_WHITEFRAME

“BLACK”,“GRAY”,"WHITE"其实是基于下表所示的系统颜色:

静态控件系统颜色
BLACKCOLOR_3DDKSHADOW
GRAYCOLOR_BTNSHADOW
WHITECOLOR_BTNHIGHLIGHT

对于上述6种样式,CreateWindow 的窗口文本字段将被忽略。
其中白色和灰色 可以与 SS_ETCHEDHORZ,SS_ETCHEDVERT 或 SS_ETCHEDFRAME 样式组合创建一个阴影框架。

常数说明
SS_ETCHEDFRAME用下凹的3D线条绘制一个边框,框内使用与底部窗体相同的颜色(透明)
SS_ETCHEDHORZ用下凹的3D线条绘制控件的上下两边,框内使用与底部窗体相同的颜色(透明)
SS_ETCHEDVERT用下凹的3D线条绘制控件的左右两边,框内使用与底部窗体相同的颜色(透明)
2.文本样式
  • SS_LEFT 创建左对齐的文本
  • SS_RIGHT 创建右对齐的文本
  • SS_CENTER 创建居中对齐的文本
2.1 文本内容:

文本右CreateWindow 的文本参数指定。可被 SetWindowText 修改。

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

2.2 颜色

这三个文本样式的子窗口背景颜色通常是 COLOR_BTNFACE,
文本本身颜色是 COLOR_WINDOWYTEXT。

可以通过俘获 WM_CTLCOLORSTATIC 消息,调用 SetTextColor() 和 SetBkColor() 分别修改文本颜色和背景颜色,同事返回背景画刷的句柄。

3. 其他

静态类还包括 SS_ICON 和 SS_USERITEM,它们被用作子窗口控件时毫无意义。

四,滚动条类

1. 样式:

滚动条样式 SBS_VERT 和 SBS_HORZ

2. 消息:

滚动条控件不发送 WM_COMMAND 消息,而是像窗口滚动条一样发送 WM_VSCROLL 和 WM_HSCROLL消息
处理滚动条消息时可用 lParam 参数区分 窗口滚动条(0) 和滚动条控件(滚动条窗口句柄),wParam 参数对于两者含义一样。

3. 尺寸:
  • 滚动条控件的窗口大小可以改变。

  • 若想创建和窗口滚动条尺寸相同的滚动条控件,可用 GetSystemMetrics() 获取信息:

    获取水平窗口滚动条的高度:
    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);
    

    区别是窗口滚动条的第一个参数是主窗口句柄,第二个参数是 SB_VERT 或 SB_HORZ 。
    颜色。

4.颜色

COLOR_SCROLLBAR 的系统颜色不再对滚动条起作用。

滚动条两端的按钮和滑块的颜色基于 COLOR_BTNFACE,COLOR_BTNHLIGHT,COLOR_BTNSHADOW,COLOR_BTNTEXT(小箭头),COLOR_DKSHADOW 以及 COLOR_BTNLIGHT。

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

可以通过处理 WM_CTLCOLORSCROLLBAR 消息,该消息返回的一个画刷来修改原来的颜色。

5. 自动键盘接口

滚动条控件还可以处理击键消息(前提是有输入焦点)

光标键滚动条消息的 wParam 值
HomeSB_TOP
EndSB_BOTTOM
Page UpSB_PAGEUP
Page DownSB_PAGEDOWN
← 或 ↑SB_LINEUP
→ 或 ↓SB_LINEDOWN

SB_TOP 和 SB_BOTTOM 只能通过键盘产生

若想让滚动条控件在鼠标单击滚动条时取得输入焦点,窗口样式参数中必须包含 WS_TABSTOP 。

例 :COLORS1
#include<windows.h>

LRESULT CALLBACK winProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam);
LRESULT CALLBACK ScrollProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam);

int idFocus;
WNDPROC OldScroll[3];

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPreInstance,LPSTR lpCmdLine,int iShowCmd)
{
	HWND hwnd;
	MSG msg;
	static TCHAR* szAppName=TEXT("myWin");
	WNDCLASS wndclass;
	wndclass.style=CS_HREDRAW|CS_VREDRAW;
	wndclass.lpfnWndProc=winProc;
	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);//Black
	wndclass.lpszMenuName=NULL;
	wndclass.lpszClassName=szAppName;
	
	if(!RegisterClass(&wndclass)){
		MessageBox(NULL,TEXT("WIN 98 不行!"),TEXT("ERROR ~ "),MB_OK);
		return 0;
	}
	hwnd=CreateWindow(szAppName,TEXT("COLOR1"),WS_OVERLAPPEDWINDOW,
				CW_USEDEFAULT,CW_USEDEFAULT,600,400,
				NULL,NULL,hInstance,NULL);
	ShowWindow(hwnd,iShowCmd);
	UpdateWindow(hwnd);
	
	while(GetMessage(&msg,NULL,0,0)){
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}

LRESULT CALLBACK winProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam){
	
	
	static int cxClient,cyClient;

	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;
	TCHAR szBuffer[10];
	
	switch(message){
		case WM_CREATE:
			hInstance=(HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE);

			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++)
			{
				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);

				hwndLabel[i]=CreateWindow(TEXT("static"),szColorLabel[i],
					WS_CHILD|WS_VISIBLE|SS_CENTER,0,0,0,0,hwnd,(HMENU)(i+3),hInstance,NULL);

				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);
				
				hBrush[i]=CreateSolidBrush(crPrim[i]);

			}
	
			hBrushStatic=CreateSolidBrush(GetSysColor(COLOR_BTNHIGHLIGHT));

			cyChar=HIWORD(GetDialogBaseUnits());
			break;
			
		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);
			break;
		case WM_SETFOCUS:
			SetFocus(hwndScroll[idFocus]);
			break;
		case WM_VSCROLL:
			i=GetWindowLong((HWND)lParam,GWL_ID);

			switch(LOWORD(wParam))
			{
			case SB_PAGEDOWN:
				color[i]+=15;
			case SB_LINEDOWN:
				color[i]=min(255,color[i]+1);
				break;
			case SB_PAGEUP:
				color[i]-=15;
			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;
			
			}
			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);
			break;
		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)
			{
				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));
			break;
		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);
			break;
		
		default:
			return DefWindowProc(hwnd,message,wParam,lParam);
			
		return 0;
	}
}
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);
}

6. 窗口子类*

子窗口控件的窗口过程在 Windows 内部,但是可以通过 GetWindowLong() (以 GWL_WNDPROC 为参数)来获取这个窗口过程的地址。
也可以通过 SetWindosLong() 设置一个新的窗口过程。
这种技术即为 “窗口子类” 。可以在自己的新子窗口过程中处理一些消息,并把其他消息传递给旧的窗口过程。

  • 新的窗口过程必须被定义为 CALLBACK 类型
  • 通过 SetWindosLong() 设置行的窗口过程,同时得到返回的旧的窗口过程地址
OldScroll = (WNDPROC)SetWindowLong(hwdnScroll,GWL_WNDPROC,(LONG)ScrollProc);
  • 通过 CallWindowProc() 来调用旧的窗口过程。
CallWindowProc(窗口过程地址,hwnd,message,wParam,lParam);
7. COLORS1 其他细节:
  • InvalidatRect() 用于使客户区右半部分失效,让Windows 把 WM_PAINT 消息放在窗口过程的消息队列中,由于 WM_PAINT 属于低优先级消息,此时仍然输入的消息不会被立即处理,若希望及时更新窗口,可以在 InvalidatRect() 后立即调用
    UpdateWindow(hwnd);
    但是这个函数可能会拖慢键盘和鼠标处理速度。

  • 处理 WM_DESTROY 消息时,清理创建的画刷:

    DeleteObject((HBRUSH)SetClassLong(hwnd,GCL_HBRBACKGROUND,(LONG)GetStockObject(WHITE_BRUSH)));
    
  • 静态文本框 通过调用SetBkColor 设置为系统颜色,只是适用于字符串所在的矩形,而不是子窗口控件的矩形。

  • 通过处理 WM_SYSCOLORCHANGE 消息解决程序运行时系统颜色被改变的问题。

五,编辑类

1. 概述

窗口类名为 “edit”

该类编辑框支持:

  • 可获得输入焦点
  • 可输入文本
  • 可移动光标
  • 可用鼠标或 Shift 键 选中部分文本
  • 可用 Ctrl + X/V/C

最简单——单行编辑框:

创建:

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

错误处理:

if (LOWORD(wParam) == ID_EDIT)
			if (HIWORD(wParam) == EN_ERRSPACE ||
				HIWORD(wParam) == EN_MAXTEXT)
				MessageBox(hwnd, TEXT("Edit control out of spae."),
2. 编辑类的样式
样式说明
ES_LEFT文本左对齐
ES_RIGHT文本右对齐
ES_CENTER文本居中
ES_MULTILINE允许多行
ES_AUTOHSCROLL自动水平滚动
ES_AUTOVSCROLL自动垂直滚动
ES_BORDER添加边框(默认没边框)
WS_HSCROLL添加水平滚动条
WS_VSCROLL添加垂直滚动条
ES_NOHIDESEL选中文本在编辑框失去输入焦点后仍然保持高亮
对于多行的编辑类,文本会自动换行,除非使用自动水平滚动,这种情况下需要回车键才会换行。
对使用这些滚动方式的多行编辑框添加滚动条,具体做法与为非子窗口添加滚动条做法一样,在窗口样式中添加 WS_HSCROLL 和 WS_VSCCROLL

预定义的多行编辑控件最多只能处理30000字符的文本。

最佳尺寸:有边框的编辑框高度应是一个字体高度的1.5倍。

3.编辑控件的通知消息

WM_COMMAND:

  • LOWORD(wParam)——子窗口ID
  • HIWORD(wParam)——通知码
  • lParam——子窗口句柄

通知码如下:

通知码说明
EN_SETFOCUS编辑控件得到了输入焦点
EN_KILLFOCUS编辑控件失去了输入焦点
EN_CHANGE编辑控件的内容将变化
EN_UPDATE编辑控件的内容已经变化
EN_ERRSPACE编辑控件没有空间了
EN_MAXTEXT编辑控件没有空间完成插入了
EN_HSCROLL编辑控件水平滚动条被单击了
EN_VSCROLL编辑控件垂直滚动条被单击了
4. 使用编辑控件
  • 使用窗口子类完成 Tab 对多个编辑控件的切换
  • 要把文本插入编辑框,可以使用 SetWindowText.
  • 从编辑控件读取文本:
iLength = GetWindowTextLength()

GetWindowText()
5.传递给编辑控件的消息(获取编辑框内容信息)
5.1 剪切,复制,清除当前选择内容
SendMessage(hwndEdit, WM_CUT, 0, 0 );
SendMessage(hwndEdit, WM_COPY, 0, 0 );
SendMessage(hwndEdit, WM_CLEAR, 0, 0);
5.2 粘贴:
SendMessage(hwndEdit, WM_PASTE, 0, 0);
5.3 获得当前选择文本的初始位置和终止位置:

终止位置——最后一个字符的位置+1

SendMessage(hwndEdit, EM_GETSEL, (WPARAM)&iStart, (LPARAM)&iEnd);
5.4 选择文本:
SendMessage(hwndEdit, EM_SETSEL, iStart, iEnd);
5.5 用其他文本代替当前选择的文本:
SendMessage(hwndEdit, EM_REPLACESEL,0 (LPARAN)szString);
5.6 获取多行编辑器的行数;
iCount = SendMessage(hwndEdit,EM_GETLINECOUNT,0,0);
5.7 对于指定行,获取从编辑缓冲区起点到这行的位移量:

(行从 0 开始计数,如果 iLine=-1,可以返回插入符号所在行的位移量)

iOffset = SendMesssage(hwndEdit,EM_LINEINDEX,iLine,0);
5.8 获取指定行的长度:
iLength = SendMessage(hwndEdit,EM_LINELENGTH,iLine,0);
5.9 复制某一行到缓冲区:
iLength = SendMessage(hwndEdit,EM_GETLINE,iLine,(LPARAM)szBuffer);

六,列表框

1. 列表框使用方法

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

被选中的项目会高亮显示

在单选列表框中:

  • 空格键选择项目。
  • -方向键可以移动光标和当前选择,可以滚动列表框的内容。
  • 上下翻页也可以移动光标来滚动列表框,但不会移动选中项
  • 单击或者双击也可以选中项
  • 按下一个字母键可移动光标和当前选择到以那个字母开头的第一项(或下一项)

在多选列表框中:

  • 空格键用于切换光标所在项目的状态。
  • 方向键取消所有一切选定的项目,并移动光标和选中项。
  • Ctrl+方向键可以只移动光标,但并不移动选中项。
  • Shift键+方向键 可以拓展选中项
  • 单击或双击多选列表框中的一个项目,会取消所有先前选定的项目,只选择被单击的项目。
  • 单击一个项目的同时按下 Shift 键 会切换该项目的选择状态而不改变任何其他项目的选择状态。
2. 列表框的样式

默认的列表框样式不能发送 WM_COMMAND 消息到父窗口,程序需要查问列表框有关选择的项目(通过发送到列表框空间的消息)。
因此,列表框总包含 LBS_NOTIFY,以便使父窗口收到 WM_COMMAND 消息。

样式说明
LBS_NOTIFY可以发送WM_COMMAND到父窗口
LBS_SORT列表框对项目进行排序
LBS_MULTIPLESEL多选列表框
WS_BORDER添加边框(默认没有)
WS_VSCROLL添加垂直滚动条
LBS_NOREDRAW防止列表框在添加项目后自我更新(可能不应该用)(应使用3.6中方法)
LBS_STANDRD包含常用列表框样式(LBS_NOTIFY|LBS_SORT|LBS_VSCROLL|WS_BORDER)
WS_SIZEBOX允许用户调整列表框尺寸
WS_CAPTION允许用户在父窗口移动它

暂时阻止自我更新可用 WM_SETREDRAW 消息

最佳尺寸:

  • 宽度: 应适应 最长字符串长度+滚动条宽度
    (滚动条宽度获得:GetSystemMetrics(SM_CXSCROLL);
  • 高度:一个字符高度 * 要出现在视图中的数量
3. 修改列表框内容
  • 最上面的项目 索引为 0
  • 通过 SendMessage 传入字符串
  • 消息的 lParam参数是一个指向空字符结尾的字符串的指针。
3.1错误分析:
  • SendMessage() 返回 LB_ERRSPACE(-2)表示:窗口过程为存储列表框的内容而用完了可用的存储空间。
  • SendMessage() 返回 LB_ERR(-1) 表示:其他原因的错误。
  • SendMessage() 返回 LB_OKAY(0) 表示:操作成功。
3.2 尾部添加——LB_ADDSTRING

会被 LBS_SORT 样式的列表框自动排序

SendMessage(hwndList,LB_ADDSTRING,0,(LPARAM)szString);
3.3 插入添加——LB_INSERTSTRING
SendMessage(hwndList,LB_INSERTSTRING,iIndex,(LPARAM)szString);
  • szString 会变成 索引值为 iIndex 的项目,之后的项目索引+1。
  • 若 iIndex = -1 则会被添加至最底部
  • 有LBS_SORT 样式的不会重新排序
  • 也可以用 LB_DIR 插入 见6
3.4 删除——LB_DELETESTRING
SendMessage(hwndList,LB_DELETESTRING,iIndex,0);
3.5 清除所有——LB_RESETCONTENT
SendMessage(hwndList,LB_RESETCONTENT,iIndex,0);
3.6 暂时抑制自动更新——WM_SETREDRAW

在需要大量增减内容时使用
关闭控件的重绘标志:

SendMessage(hwndList,WM_SETREDRAW,FALSE,0);

修改完之后,开启重绘:

SendMessage(hwndList,WM_SETREDRAW,TRUE,0);
4. 项目的选择和提取
4.1 获取项目数——LB_GETCOUNT
iCount = SendMessage(hwndList,LB_GETCOUNT,0,0);
4.2 (单选)突出一个默认选中项——LB_SETCURSEL
SendMessage(hwndList,LB_SETCURSEL,iINdex,0);

若 iINdex = -1 将取消选中所有项

4.3 (单选)根据起始字符选择项目选择——LB_SELECTSTRING
iIndex = SendMessage(hwndList,LB_SELECTSTRING,iINdex,(LPARAM)szSearchString);

参数中的 iIndex 是指定从哪一个索引开始搜索,若该参数为-1则从顶端开始查找,返回被选中项目的索引,没有匹配的则返回 LB_ERR。

4.4 (单选)获得选中项的索引值——LB_GETCURSEL
iIndex = SendMessage(hwndList,LB_GETCUESEL,0,0);

没有被选中返回 LB_ERR

4.5 获取列表框某一项目字符串长度——LB_GETTEXTLEN
iLength = SendMessage(hwndList,LB_GETTEXTLEN,iIndex,0);
4.6 复制列表框某一项到文本缓冲区——LB_GETTEXT
iLength = SendMessage(hwndList,LB_GETTEXT,iIndex,(LPARAM)szBuffer);

预先准备好足够大的缓冲区(根据4.5)

4.7 (多选)设置某一项目的选择状态——LB_SETSEL
SendMessage(hwndList,LB_SETSEL,wParam,iIndex
);

若 wParam 为非零值,则选择并高亮该项目,是0,则取消选择。
若lParam(iIndex)是-1,要么所有项目都被选中,要么所有项目都取消选中。

4.8 (多选?)检验某一项目的选择状态——LB_GETSEL
iSelect = SendMessage(hwndList,LB_GETSEL,iIndex,0
);

选中则返回非零值,否则返回0

5. 接收来自列表框的消息

一个列表框会发送 WM_COMMAND 消息到其父窗口,消息参数含义与按钮,编辑类一样:

  • LOWORD(wParam) ——子窗口ID
  • HIWORD(wParam)——通知码
  • lParam——子窗口句柄

通知码:

通知码说明
LBN_ERRSPACE-2列表框已经用尽了它的空间
LBN_SELCHANGE1当前选择发生了变化
LBN_DBLCLK2某个项目已被鼠标双击
LBN_SELCANCEL3
LBN_SETFOCUS4
LBN_KILLFOCUS5

注:样式包含 LBS_NOTIFY ,列表框才会发送LBN_SELCHANGE 和 LBN_DBLCLK 消息

简单的列表框程序:

#include <windows.h>    
 
#define ID_LIST		1
#define ID_TEXT		2
 
LRESULT 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);
}

6.列出文件——LB_DIR
SendMessage(hwdnList,LB_DIR,iAttr,(LPARAM)szFileSpec);

功能:将文件目录写入列表框。这个木剑目录可以包括子目录和有效的磁盘驱动器。

文件属性代码

iAttr ——文件属性代码
文件属性代码的最低字节可以是下表数值的组合:

iAttr数值属性
DDL_READWRITE0x0000普通文件
DDL_READONLY0x0001只读文件
DDL_HIDDEN0x0002隐藏文件
DDL_SYSTEM0x0004系统文件
DDL_DIRECTORY0x0010子目录
DDL_ARCHIVE0x0020设置了存档位的文件

最高字节提供一些额外的搜索条件:

iAttr数值选项
DDL_DRIVES0x4000包括驱动器字符
DLL_EXCLUSIVE0x8000只搜索指定的值

注:DDL =“dialog directory list”(对话框目录列表)

若 iAttr 是 DDL_READWRITE,列表框会列出 普通文件,只读文件以及存档位已设置的文件

若iAttr 是 DDL_DIRECTORY,除了以上文件还有带方括号的目录名以及子目录名

组合值 DDL_DRIVES|DDL_DIRECTORY 会将这个列表拓展到包括所有有效驱动器,驱动器字符用短划线分割

iAttr 的最高位(DDL_EXLUSIVE)被设置后,只列出指定的一些文件,比如 DDL_EXCLUSIVE|DDL_ARCHIVE 只列出自从上次备份处理以来所有被修改过文件。

文件排序

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

使用 LBS_SORT 消息后:
①先是满足文件限定符的所有文件的名称
②然后(可选的)列出子目录的名称
第一个子目录:
[..]表示返回上一级目录 (根目录没有该符号)

③最后,特定的子目录名称:
[SUBDIR]

④后面紧跟(可选的)是有效磁盘驱动区的清单:
[-A-]

例 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编码的文本就会乱码。这设计到很多编码的转换了,将在以后改进。


上述部分代码(HEAD有关程序)转自CSDN的sesiria

原文:https://blog.csdn.net/sesiria/article/details/51817740

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值