本节中的示例显示了应用程序如何从键盘接收字符,将其显示在窗口的客户区中,并使用每个输入的字符更新插入符的位置。它还演示了如何按照左箭头键,右箭头键,首页键和结束键击来移动插入符号,并显示如何突出显示所选文本以响应SHIFT + RIGHT ARROW键组合。
在WM_CREATE消息的处理期间,示例中显示的窗口过程分配一个用于存储键盘输入的64K缓冲区。它还检索当前加载的字体的度量,保存字体的字符的高度和平均宽度。高度和宽度用于处理WM_SIZE消息,以根据客户端区域的大小计算行长度和最大行数。
窗口过程在处理WM_SETFOCUS消息时创建并显示插入符号。处理WM_KILLFOCUS消息时,它隐藏和删除插入符号。
处理WM_CHAR消息时,窗口过程显示字符,将它们存储在输入缓冲区中,并更新插入符位置。窗口过程还将制表符字符转换为四个连续的空格字符。Backspace,换行符和转义字符会产生一个哔声,但是没有另外处理。
当处理WM_KEYDOWN消息时,窗口过程执行左,右,结束和主页插入符移动。在处理右箭头键的动作时,窗口过程将检查SHIFT键的状态,如果是“关”,则在插入符号移动时选择插入符右侧的字符。
请注意,以下代码将被编写,以便可以以Unicode或ANSI编译。如果源代码定义Unicode,则字符串将以Unicode字符处理;否则,它们被作为ANSI字符处理。
#define BUFSIZE 65535
#define SHIFTED 0x8000
LONG APIENTRY MainWndProc(hwndMain,uMsg,wParam,lParam)
HWND hwndMain;
UINT uMsg;
UINT wParam;
LONG lParam;
{
HDC hdc; /* handle of device context */
TEXTMETRIC tm; /* structure for text metrics */
static DWORD dwCharX; /* average width of characters */
static DWORD dwCharY; /* height of characters */
static DWORD dwClientX; /* width of client area */
static DWORD dwClientY; /* height of client area */
static DWORD dwLineLen; /* line length */
static DWORD dwLines; /* text lines in client area */
static int nCaretPosX = 0; /* horizontal position of caret */
static int nCaretPosY = 0; /* vertical position of caret */
static int nCharWidth = 0; /* width of a character */
static int cch = 0; /* characters in buffer */
static int nCurChar = 0; /* index of current character */
static PTCHAR pchInputBuf; /* address of input buffer */
int i, j; /* loop counters */
int cCR = 0; /* count of carriage returns */
int nCRIndex = 0; /* index of last carriage return */
int nVirtKey; /* virtual-key code */
TCHAR szBuf[128]; /* temporary buffer */
TCHAR ch; /* current character */
PAINTSTRUCT ps; /* required by BeginPaint */
RECT rc; /* output rectangle for DrawText */
SIZE sz; /* string dimensions */
COLORREF crPrevText; /* previous text color */
COLORREF crPrevBk; /* previous background color */
开关(uMsg){
case WM_CREATE:
/ *获取当前字体的指标。*/
hdc = GetDC(hwndMain);
GetTextMetrics(hdc, &tm);
ReleaseDC(hwndMain, hdc);
/ *保存平均字符宽度和高度。*/
dwCharX = tm.tmAveCharWidth;
dwCharY = tm.tmHeight;
/ *分配缓冲区以存储键盘输入。*/
pchInputBuf = (LPTSTR) GlobalAlloc(GPTR,
BUFSIZE * sizeof(TCHAR));
return 0;
case WM_SIZE:
/ *保存客户区域的新宽度和高度。*/
dwClientX = LOWORD(lParam);
dwClientY = HIWORD(lParam);
/*
*计算一行的最大宽度
*客户区域的最大行数。
*/
dwLineLen = dwClientX - dwCharX;
dwLines = dwClientY / dwCharY;
break;
case WM_SETFOCUS:
/*
*创建,定位和显示插入符号
*窗口接收键盘焦点。
*/
CreateCaret(hwndMain, (HBITMAP) 1, 0, dwCharY);
SetCaretPos(nCaretPosX, nCaretPosY * dwCharY);
ShowCaret(hwndMain);
break;
case WM_KILLFOCUS:
/*
*当窗户丢失时,隐藏并摧毁插入符号
*键盘焦点。
*/
HideCaret(hwndMain);
DestroyCaret();
break;
case WM_CHAR:
开关(wParam){
case 0x08: /* backspace */
case 0x0A: /* linefeed */
case 0x1B: /* escape */
MessageBeep(0xFFFFFFFF);
return 0;
case 0x09: /* tab */
/ *将标签转换为四个连续空格。*/
for (i = 0; i < 4; i++)
SendMessage(hwndMain, WM_CHAR, 0x20, 0);
return 0;
case 0x0D: /* carriage return */
/*
*记录回车并定位
*在新行开始的插入符号。
*/
pchInputBuf[cch++] = 0x0D;
nCaretPosX = 0;
nCaretPosY += 1;
break;
默认值:/ *可显示字符* /
ch = (TCHAR) wParam;
HideCaret(hwndMain);
/*
*获取字符的宽度和输出
* 人物。
*/
hdc = GetDC(hwndMain);
GetCharWidth32(hdc,(UINT)wParam,(UINT)wParam,
&nCharWidth);
TextOut(hdc,nCaretPosX,nCaretPosY * dwCharY,
&ch, 1);
ReleaseDC(hwndMain, hdc);
/ *将字符存储在缓冲区中。*/
pchInputBuf[cch++] = ch;
/*
*计算新的水平位置
*插入符号。en如果位置超过最大值,
*插入回车并移动插入符号
*到下一行的开头。
*/
nCaretPosX += nCharWidth;
if((DWORD)nCaretPosX > dwLineLen){
nCaretPosX = 0;
pchInputBuf[cch++] = 0x0D;
++nCaretPosY;
}
nCurChar = cch;
ShowCaret(hwndMain);
break;
}
SetCaretPos(nCaretPosX, nCaretPosY * dwCharY);
break;
case WM_KEYDOWN:
开关(wParam){
case VK_LEFT: /* LEFT ARROW */
/*
*插入符号只能移动到开头
*当前行。
*/
if(nCaretPosX > 0){
HideCaret(hwndMain);
/*
*检索左边的字符
*插入符号,计算字符
* width,然后从中减去宽度
*插入符号的当前水平位置
*获得新职位。
*/
ch = pchInputBuf[--nCurChar];
hdc = GetDC(hwndMain);
GetCharWidth32(hdc, ch, ch, &nCharWidth);
ReleaseDC(hwndMain, hdc);
nCaretPosX = max(nCaretPosX - nCharWidth,
0);
ShowCaret(hwndMain);
}
break;
case VK_RIGHT: /* RIGHT ARROW */
/*
*插入物移动到右边或当一个马车
*返回遇到,到了开始
*下一行。
*/
if(nCurChar < cch){
HideCaret(hwndMain);
/*
*检索右侧的字符
*插入符号。如果是回车,
*在开头位置插入符号
*下一行。
*/
ch = pchInputBuf[nCurChar];
if (ch == 0x0D) {
nCaretPosX = 0;
nCaretPosY++;
}
/*
*如果角色不是马车
*返回,检查看是否SHIFT
*键已关闭如果是,则反转文本
*颜色并输出字符。
*/
else {
hdc = GetDC(hwndMain);
nVirtKey = GetKeyState(VK_SHIFT);
if(nVirtKey & SHIFTED){
crPrevText = SetTextColor(hdc,
RGB(255, 255, 255));
crPrevBk = SetBkColor(hdc,
RGB(0,0,0));
TextOut(hdc,nCaretPosX,
* nCaretPosY dwCharY,
&ch, 1);
SetTextColor(hdc, crPrevText);
SetBkColor(hdc, crPrevBk);
}
/*
*获取字符的宽度
*计算新的水平
*插入符号的位置。
*/
GetCharWidth32(hdc, ch, ch, &nCharWidth);
ReleaseDC(hwndMain, hdc);
nCaretPosX = nCaretPosX + nCharWidth;
}
nCurChar++;
ShowCaret(hwndMain);
break;
}
break;
case VK_UP: /* UP ARROW */
case VK_DOWN: /* DOWN ARROW */
MessageBeep(0xFFFFFFFF);
return 0;
case VK_HOME: /* HOME */
/*
*将插入符的位置设置在左上方
*客户区的角落。
*/
nCaretPosX = nCaretPosY = 0;
nCurChar = 0;
break;
case VK_END: /* END */
/ *将插入符号移动到文本的末尾。*/
for (i=0; i < cch; i++) {
/*
*计算回车并保存
*最后一个索引。
*/
if (pchInputBuf[i] == 0x0D) {
cCR++;
nCRIndex = i + 1;
}
}
nCaretPosY = cCR;
/*
*复制最后一个托架之间的所有文本
*返回和键盘输入的结束
*缓冲区到临时缓冲区。
*/
for (i = nCRIndex, j = 0; i < cch; i++, j++)
szBuf[j] = pchInputBuf[i];
szBuf[j] = TEXT('\0');
/*
*检索文本范围并使用它
*设置水平位置
*插入符号。en
*/
hdc = GetDC(hwndMain);
GetTextExtentPoint32(hdc,szBuf,lstrlen(szBuf),
&sz);
nCaretPosX = sz.cx;
ReleaseDC(hwndMain, hdc);
nCurChar = cch;
break;
默认:
break;
}
SetCaretPos(nCaretPosX, nCaretPosY * dwCharY);
break;
case WM_PAINT:
if (cch == 0) /* nothing in input buffer */
break;
hdc = BeginPaint(hwndMain, &ps);
HideCaret(hwndMain);
/*
*设置裁剪矩形,然后绘制文本
* 进去。
*/
SetRect(&rc, 0, 0, dwLineLen, dwClientY);
DrawText(hdc, pchInputBuf, -1, &rc, DT_LEFT);
ShowCaret(hwndMain);
EndPaint(hwndMain, &ps);
break;
.
./ *处理其他消息。*/
.
case WM_DESTROY:
PostQuitMessage(0);
/ *释放输入缓冲区。*/
GlobalFree((HGLOBAL) pchInputBuf);
UnregisterHotKey(hwndMain, 0xAAAA);
break;
默认:
return DefWindowProc(hwndMain, uMsg, wParam, lParam);
}
return NULL;
}