9.4.1 滚动条控件
(1)窗口滚动条与滚动条控件的比较
|
窗口滚动条 |
滚动条控件 |
消息 |
发送WM_VSCROLL、WM_HSCROLL消息。不发送WM_COMMAND消息。wParam参数的意义是一样的。lParam:当消息来自窗口滚动条时为NULL,来自滚动条控件时为滚动条的句柄。 |
|
宽度或高度 |
固定大小 //水平滚动条高度 GetSysMetrics(SM_CYHSCROLL); //垂直滚动条宽度 GetSysMetrics(SM_CYVSCROLL) |
1、大小、位置均可设定; 2、在CreateWindow或MoveWindow函数中指定,大小可自定义。 |
窗口样式 |
WS_VSCROLL:垂直滚动条(在窗口右侧) WS_HSCROLL:水平滚动条(在窗口下方) |
可用滚动条样式和尺寸 SBS_VERT、SBS_HORZ、 S SBS_TOPALIGN、 BS_BOTTOMALIGN、SBS_LEFTALIGN、SBS_RIGHTALIGN等。 |
调用函数 的参数 |
SetScrollInfo(hwnd,SB_VERT, &si,bRedraw); |
SetScrollInfo(hwndScroll,SB_CTL, &si,bRedraw); |
(2)滚动条的颜色
①滚动条两端的按钮及滑块:COLOR_BTNFACE、COLOR_BTNHILIGHT、COLOR_BTNSHADOW、COLOR_BTNTEXT(给小箭头用)、COLOR_DKSHADOW及COLOR_BTNLIGHT
②两端按钮之间的大片区域:COLOR_BTNFACE、COLOR_BTNHIGHLIGHT的某种组合。
9.4.2 COLORS1程序
(1)窗口子类化
①用自定义窗口过程(ScrollProc)替换Windows的内部窗口过程
OldScroll[i]=(WNDPROC)SetWindowLong(hwndScroll[i], GWL_WNDPROC, (LONG)ScrollProc);
②调用旧的滚动条窗口过程
CallWindowProc(OldScroll[id],hwnd, message, wParam, lParam);
(2)主窗口背景着色
①准备好背景画刷:新建画刷→存入窗口类结构→删除旧画刷
DeleteObject((HBRUSH)
SetClassLong(hwnd, GCL_HBRBACKGROUND,(LONG)
CreateSolidBrush(RGB(color[0],color[1], color[2]))));
②终止程序时清除画刷
DeleteObject((HBRUSH)
SetClassLong(hwnd, GCL_HBRBACKGROUND,(LONG)GetStockObject(WHITE_BRUSH)));
(3)滚动条和静态文本着色
①3个滚动条背景色:hBrush[i] = CreateSolidBrush(crPrim[i]);
②在WM_CTLCOLORSCROLLBAR中return (LRESULT)hBrush[i],返回画刷,即可着色。
③静态文本在WM_CTLCOLORSTATIC中通过SetBkColor和SetTextColor为文本着色。
【Color1程序】
/*------------------------------------------------------------ COLORS1.C -- Colors Using Scroll Bars (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #include <windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT ScrollProc(HWND, UINT, WPARAM, LPARAM); int idFocus; //当前选中的滚动条 WNDPROC OldScroll[3]; //原3个滚动条控件的窗口过程 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("Colors1"); HWND hwnd; MSG msg; WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; 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; if (!RegisterClass(&wndclass)) { MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, // window class name TEXT("Color Scroll1"), // 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); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } 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 TCHAR* szColorLabel[] = { TEXT("Red"), TEXT("Green"), TEXT("Blue") }; TCHAR szBuffer[10]; static int cxChar, cyChar; HINSTANCE hInstance; static RECT rcColor; static int color[3]; //三个滚动条当前的颜色值 int i, cxClient, cyClient; switch (message) { case WM_CREATE: //hInstance = ((LPCREATESTRUCT)lParam)->hInstance; hInstance = (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE); //创建一个白色矩形区,用来放置控件,窗口ID为9. hwndRect = CreateWindow(TEXT("static"), NULL, WS_CHILD | WS_VISIBLE | SS_WHITERECT, 0, 0, 0, 0, hwnd, (HMENU)9, hInstance, NULL); for (int i = 0; i< 3; i++) { //创建三个滚动条,范围0-255,ID分别为0,1.2 hwndScroll[i] = CreateWindow(TEXT("scrollbar"), NULL, WS_CHILD | WS_VISIBLE | WS_TABSTOP | SBS_VERT, //垂直,可接受Tab键 0, 0, 0, 0, hwnd, (HMENU)i, hInstance, NULL); SetScrollRange(hwndScroll[i], SB_CTL, 0, 255, FALSE); SetScrollPos(hwndScroll[i], SB_CTL, 0, FALSE); //3个颜色名称为"Red"、"Green"、"Blue"的标签,ID分别为3,4,5 hwndLabel[i] = CreateWindow(TEXT("static"), szColorLabel[i], WS_CHILD | WS_VISIBLE | SS_CENTER, 0, 0, 0, 0, hwnd, (HMENU)(i + 3), hInstance, NULL); //3种颜色值的标签,ID分别为6,7,8 hwndValue[i] = CreateWindow(TEXT("static"), TEXT("0"), WS_CHILD | WS_VISIBLE | SS_CENTER, 0, 0, 0, 0, hwnd, (HMENU)(i + 6), hInstance, NULL); //3个滚动条的背景画刷 hBrush[i] = CreateSolidBrush(crPrim[i]); OldScroll[i] = (WNDPROC)SetWindowLong(hwndScroll[i], GWL_WNDPROC, (LONG)ScrollProc); } hBrushStatic = CreateSolidBrush(GetSysColor(COLOR_BTNHIGHLIGHT)); cxChar = LOWORD(GetDialogBaseUnits()); 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 (int i = 0; i < 3; i++) { //设置滚动条在主窗口大小和位置:宽cxClient/14,高cyClient -4*cyChar; MoveWindow(hwndScroll[i], (2 * i + 1)*cxClient / 14, 2 * cyChar, cxClient / 14, cyClient - 4 * cyChar, TRUE); MoveWindow(hwndLabel[i], (2 * i + 1)*cxClient / 14, cyChar / 2, cxClient / 14, cyChar, TRUE); MoveWindow(hwndValue[i], (2 * i + 1)*cxClient / 14, cyClient - 3 * cyChar / 2, cxClient / 14, cyChar, TRUE); } SetFocus(hwnd); return 0; case WM_VSCROLL: //获取子窗口ID i = GetWindowLong((HWND)lParam, GWL_ID); switch (LOWORD(wParam)) { case SB_PAGEDOWN: //每次增长16; color[i] += 16; break; case SB_PAGEUP: color[i] -= 16; break; case SB_LINEDOWN: color[i] += 1; break; case SB_LINEUP: 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; } color[i] = max(0, min(255, color[i])); SetScrollPos(hwndScroll[i], SB_CTL, color[i], TRUE); wsprintf(szBuffer, TEXT("%i"), color[i]); //%i与%d相同 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: //wParam:DC,lParam:滚动条句柄 i = GetWindowLong((HWND)lParam, GWL_ID); return (LRESULT)hBrush[i]; //须返回画刷句柄 case WM_CTLCOLORSTATIC://wParam:DC,lParam:静态类文本的句柄 i = GetWindowLong((HWND)lParam, GWL_ID); if (i >= 3 && i <= 8) { SetBkColor((HDC)wParam, GetSysColor(COLOR_BTNHIGHLIGHT)); SetTextColor((HDC)wParam, crPrim[i % 3]); return (LRESULT)hBrushStatic; } break; case WM_SYSCOLORCHANGE: DeleteObject(hBrushStatic); hBrushStatic = CreateSolidBrush(GetSysColor(COLOR_BTNHIGHLIGHT)); return 0; case WM_SETFOCUS: SetFocus(hwndScroll[idFocus]); return 0; case WM_DESTROY: //将主窗口画刷设为白色 DeleteObject((HBRUSH) SetClassLong(hwnd, GCL_HBRBACKGROUND, (LONG)GetStockObject(WHITE_BRUSH))); DeleteObject(hBrushStatic); for (int i = 0; i < 3; i++) DeleteObject(hBrush[i]); PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); } //窗口子类化 LRESULT ScrollProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { int id = GetWindowLong(hwnd, GWL_ID);//获子窗口ID switch (message) { case WM_KEYDOWN: if (wParam == VK_TAB) { SetFocus(GetDlgItem(GetParent(hwnd), (id + 1) % 3)); } break; case WM_SETFOCUS: idFocus = id; break; } //调用子窗口旧的窗口过程 return CallWindowProc(OldScroll[id], hwnd, message, wParam, lParam); }
9.5.1 编辑类的样式
样式 |
说明 |
ES_LEFT |
文本对齐方式 |
ES_RIGHT |
|
ES_CENTER |
|
ES_MULTILINE |
多行编辑控件 |
ES_AUTOHSCROLL |
默认会自动文本,加这后不会自动换行,要按回车键。 |
ES_AUTOVSCROLL |
垂直滚动条 |
ES_NOHIDESEL |
失去焦,选中时仍高亮显示 |
9.5.2 编辑控件的通知消息:WM_COMMAND
参数 |
含义 |
|
lParam |
子窗口句柄 |
|
wParam |
LOWORD(wParam):子窗口ID |
|
HIWORD(wParam):通知码 |
EN_SETFOCUS:得到焦点 EN_KILLFOCUS:失去焦点 EN_CHANGE: 内容改变 EN_UPDATE: 内容己变化 EN_ERRSPACE: 没有空间了 EN_MAXTEXT: 输入超过最大长度 EN_HSCROLL: 水平滚动条被单击 EN_VSCROLL: 垂直滚动条被单击 |
9.5.3 使用编辑控件
①SetWindowText:输入文本
②GetWindowText:读取文本
③GetWindowTextLength:获得文本长度
9.5.4 传递消息给编辑控件
操作 |
消息 |
复制、剪切、 清除、粘贴 |
SendMessage(hwndEdit,WM_COPY,0,0); SendMessage(hwndEdit,WM_CUT,0,0); SendMessage(hwndEdit,WM_CLEAR,0,0); SendMessage(hwndEdit,WM_PASTE,0,0); |
获取选择文本的位置 |
SendMessage(hwndEdit,EM_GETSEL,(WPARAM&iStart,(LPARAM)&iEND); |
选择文本 |
SendMessage(hwndEdit,EM_SETSEL,iStart,iEnd); |
获得行数 |
iCount = SendMessage(hwndEdit,EM_LINECOUNT,0,0); |
编辑缓冲区起点到指定行的位移量 |
iOffset = SendMessage(hwndEdit,EM_LINELENGTH,iLine,0); //如果iLine =-1,则返回插入符号所在行的位移量。 |
获到某行的长度 |
iLength = SendMessage(hwndEdit,EM_LINELENGTH,iLine,0); |
复制一行到缓冲区 |
iLength = SendMessage(hwndEdit,EM_GETLINE,iLine,(LPARAM)szBuffer |
【PopPad1程序】
/*------------------------------------------------------------ POPPAD1.C -- Popup Editor using child window edit box (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #include <windows.h> #define ID_EDIT 1 static TCHAR szAppName[] = TEXT("PopPad1"); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { HWND hwnd; MSG msg; WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; 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; if (!RegisterClass(&wndclass)) { MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, // window class name TEXT("edit"), // 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); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static HWND hwndEdit; switch (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_COMMAND: if (LOWORD(wParam) == ID_EDIT) { if (HIWORD(wParam) == EN_ERRSPACE || HIWORD(wParam) == EN_MAXTEXT) { MessageBox(hwnd, TEXT("Edit Control out of space."), szAppName, MB_OK | MB_ICONSTOP); } } return 0; case WM_SIZE: MoveWindow(hwndEdit, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
键盘操作 |
单选列表框 |
多选列表框 |
空格键 |
选择光标所在项 |
切换选中状态 |
方向键 |
移动光标和当前的选择 |
取消以前所选,并移动光标和选中项 |
翻页键 |
移动光标,但不移动选择项 |
|
字母键 |
移动和选择以该字母开头的第一项 |
|
Ctrl+方向 |
移动光标,但不移动选中项 |
|
Shift+方向 |
扩展选中项 |
9.6.1 列表框的样式
样式 |
含义 |
LBS_NOTIFY |
默认的列表框样式不能发送WM_COMMAND到父窗口,须指定该样式才行 |
LBS_SORT |
排序 |
LBS_MULTIPLESEL |
多选 |
LBS_NOREDRAW |
新增项目默认不会自我更新,可在WM_SETREDRAW中设置 |
LBS_STANDARD |
标准列表框:LBS_NOTIFY|LBS_SORT|WS_VSCROLL|WS_BORDER |
★设定列表框的宽度:最长字符串长度+滚动条的宽度
★设定列表框的高度:1个字符的高度*视图中项目的数量
9.6.2 向列表框中添加字符串
操作 |
SendMessage: 返回值——LB_ERRSPACE或LB_ERR或LB_OKAY |
在列表框最后增加一项 |
(hwndList,LB_ADDSTRING,0,(LPARAM)szString); //如果LBS_SORT则会插到顺序后相应的位置。 |
插入到指定位置 |
hwndList,LB_INSERTSTRING,iIndex,(LPARAM)szString) //当iIndex=-1时,会被添加到最底部。 |
删除索引位置处的一个字符串 |
(hwndList,LB_DELETESTRING,iIndex,0); |
清除所有项目 |
(hwndList,LB_RESETCONTENT,iIndex,0); |
开关控件重绘标志 |
(hwndList,WM_SETREDRAW,FALSE,0); (hwndList,WM_SETREDRAW,TRUE,0); |
9.6.3 项目的选择和提取
(1)获取列表框项目数量:iCount=SendMessage(hwndList,LB_GETCOUNT,0,0)
(1)单选列表框
单选列表框操作 |
相应代码 |
突出选择某项 |
SendMessage(hwndList,LB_SETCURSEL,iIndex,0); //lParam为-1时,取消选中所有项 |
根据起始字符选择一项 |
SendMessage(hwndList,LB_SELECTSTRING,iIndex, (LPARAM)szSerchString); //如果参数iIndex=-1,那么从顶端开始查找。 //返回值:被选中的索引或没有匹配时为LB_ERR |
获取当前选中项的索引 |
iIndex = SendMessage(hwndList,LB_GETCURSEL,0,0) |
获取某项字符串长度 |
iLength = SendMessage(hwndList,LB_GETTEXTLEN,iIndex,0) |
读取项目到缓冲区 |
iLength =SendMessage(hwndList,LB_GETTEXT,iIndex, (LPARAM)szBuffer); |
(3)多选列表框(不能使用LB_SETCURSEL,LB_GETCURSEL或LB_SELECTSTRING)
操作 |
相应代码 |
设置某项选择状态 (不影响其他项) |
SendMessage(hwndList,LB_SETSEL,wParam,iIndex); //wParam非零时,选中并高亮该项,为0时取消选择 //lParam是-1时,在选择和取消所有项之间切换 |
检查选择状态 |
iSelect = SendMessage(hwndList,LB_GETSEL,iIndex,0); //iSelect非零,表示选中。为零时,未选中 |
9.6.4 接收来自列表框的消息
参数 |
含义 |
|
lParam |
子窗口句柄 |
|
wParam |
LOWORD(wParam):子窗口ID |
|
HIWORD(wParam):通知码 |
LBN_ERRSPACE: 空间不够 LBN_SELCHANGE:当前选择发生变化 LBN_DBLCLK: 双击 LBN_SELCANCEL:取消选择 LBN_SETFOCUS: 得到焦点 LBN_KILLFOCUS:失去焦点 |
【ENVIRON.C程序】
(1)环境变量格式
(2)获取和释放环境变量块GetEnvironmentStrings、FreeEnvironmentStrings
(3)获取环境变量 GetEnvironmentVariable
效果图:
/*------------------------------------------------------------ ENVIRON.C -- Environment List Box (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #include <windows.h> #define ID_LIST 1 #define ID_TEXT 2 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("Environ"); HWND hwnd; MSG msg; WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; 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); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass)) { MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } 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); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } void FillListBox(HWND hwndList) { TCHAR *pVarBlock, *pVarCurr, *pVarBeg, *pVarEnd, *pVarName; int iLength; //获得环境变量的指针 pVarCurr = pVarBlock = GetEnvironmentStrings(); while (*pVarCurr) { if (*pVarCurr != '=') //跳过无意义的“=::=::”或"=E:=E:ABC"格式的字符串 { pVarBeg = pVarCurr; //变量名的开始位置。注意环境变量的格式varName=value while (*pVarCurr++ != '='); //扫描到‘=’号 pVarEnd = pVarCurr - 1; //pVarCurr指向'='号 iLength = pVarEnd - pVarBeg; //变量名的长度 //分配内存给变量名 pVarName = calloc(iLength + 1, sizeof(TCHAR)); //变量名加个' '结束,所以iLength+1 CopyMemory(pVarName, pVarBeg, iLength*sizeof(TCHAR)); pVarName[iLength] = '