第九章 子窗口控件
子窗口可以作为控制屏幕图形显示,响应用户输入,以及在有重要输入事件的时候通知另一窗口。
标准子窗口控件,按钮,复选框,编辑框,列表框,组合框,文本字符串和滚动条。
可以使用CreateWindow来创建子窗口控件,或者在程序的资源脚本里编辑好各种属性。
使用预定义控件不需要再注册相应的子窗口类,这些类已经存在于windows中并且已经有了预定义的名称。
在调用CreateWindow时,只需要使用该名称作为窗口类的参数即可。
在窗口表明直接创建子窗口,所涉及的任务比使用对话框内的子窗口控件更底层。对于对话框,对话框管理器在你的程序和控件之间增加了一个隔离层。
比如支持TAB,方向键切换焦点。 子窗口控件可以得到输入焦点,可是一旦得到焦点,它就无法把输入焦点交回给其父窗口。
标准控件, 通用控件。
9.1 按钮类
#include
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返回类似的数据
每个子窗口的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
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
#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
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擦除背景
InvalidateRect(hwnd, &rcColor, TRUE);
UpdateWindow(hwnd); 立即更新 不过可能会拖慢键盘和鼠标处理速度。
在处理WM_DESTORY消息时, 删除当前创建的画刷
DeleteObject((HBRUSH)
SetClassLong(hwnd, GCL_HBRBACKGROUND, (LONG)
GetStockObject((WHITE_BRUSH))));
滚动条着色是通过处理 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
#define ID_EDIT 1
LRESULT 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
#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);
}
运行结果
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);
9.6.7 Windows的HEAD程序
#include
#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
#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编码的文本就会乱码。这设计到很多编码的转换了,将在以后改进。