16,550
社区成员
发帖
与我相关
我的任务
分享// 简单的文字编辑器,按下 Escape 键、缩放窗口、改变键盘输入语言时都会清除窗口的内容。
#include<windows.h>
// 返回坐标 x,y 处字符引用
#define BUFFER(x,y) *(pBuffer + y * cxBuffer + x)
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("Typer") ;
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 (GRAY_BRUSH) ;// 灰色背景
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox ( NULL, TEXT ("程序请求 Windows NT!"), szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName,
TEXT ("打字程序"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL) ;
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 DWORD dwCharSet = DEFAULT_CHARSET ; // 默认字符集
// 字符尺寸及客户区尺寸
static int cxChar, cyChar, cxClient, cyClient,
// 以字符为单位的x,y坐标及插入符坐标
cxBuffer, cyBuffer, xCaret, yCaret ;
static TCHAR *pBuffer = NULL ; // 字符缓冲区
HDC hdc ;
int x, y, i ;
PAINTSTRUCT ps ;
TEXTMETRIC tm ;
switch (message)
{
// 更改字符集
case WM_INPUTLANGCHANGE:// 改变键盘布局发送此消息
dwCharSet = wParam ;
// 失败
// 得到单个字符尺寸
case WM_CREATE:
hdc = GetDC (hwnd) ;
// CreateFont 第 9 个参数设为字符集ID,第 13 个参数设定为 FIXED_PITCH
SelectObject (hdc, CreateFont (0, 0, 0, 0, 0, 0, 0, 0,
dwCharSet, 0, 0, 0, FIXED_PITCH, NULL)) ;
GetTextMetrics (hdc, &tm) ;
cxChar = tm.tmAveCharWidth ;
cyChar = tm.tmHeight ;
DeleteObject (SelectObject (hdc, GetStockObject (SYSTEM_FONT))) ;
ReleaseDC (hwnd, hdc) ;
// 失败
case WM_SIZE:
// 得到窗口尺寸(以像素为单位)
if (message == WM_SIZE)
{
cxClient = LOWORD (lParam) ;
cyClient = HIWORD (lParam) ;
}
// 计算窗口尺寸(以字符为单位)
cxBuffer = max (1, cxClient / cxChar) ;
cyBuffer = max (1, cyClient / cyChar) ;
// 为缓冲区分配内存
if (pBuffer != NULL) // 释放先前的内存
free (pBuffer) ;
// 分配能容纳当前窗口最大数量字符的内存
pBuffer = (TCHAR *) malloc (cxBuffer * cyBuffer * sizeof (TCHAR)) ;
// 初始为空字符
for (y = 0 ; y < cyBuffer ; y++)
for (x = 0 ; x < cxBuffer ; x++)
BUFFER(x,y) = ' ' ;
// 设置插入符到左上角
xCaret = 0 ;
yCaret = 0 ;
if (hwnd == GetFocus ()) // 窗口得到焦点
// 定位插入符到左上角( 0, 0 )
SetCaretPos (xCaret * cxChar, yCaret * cyChar) ;
InvalidateRect (hwnd, NULL, TRUE) ;// 清空内容,发送 WM_PAINT 消息
return 0 ;
case WM_SETFOCUS: // 设置焦点
// 创建并显示插入符
CreateCaret (hwnd, NULL, cxChar, cyChar) ;
SetCaretPos (xCaret * cxChar, yCaret * cyChar) ;
ShowCaret (hwnd) ;
return 0 ;
case WM_KILLFOCUS:
// 隐藏并销毁插入符
HideCaret (hwnd) ;
DestroyCaret () ;
return 0 ;
case WM_KEYDOWN: // 键盘消息
switch (wParam)
{
case VK_HOME:
xCaret = 0 ;
break ;
case VK_END:
xCaret = cxBuffer - 1 ;
break ;
case VK_PRIOR:
yCaret = 0 ;
break ;
case VK_NEXT:
yCaret = cyBuffer - 1 ;
break ;
case VK_LEFT:
xCaret = max (xCaret - 1, 0) ;
break ;
case VK_RIGHT:
xCaret = min (xCaret + 1, cxBuffer - 1) ;
break ;
case VK_UP:
yCaret = max (yCaret - 1, 0) ;
break ;
case VK_DOWN:
yCaret = min (yCaret + 1, cyBuffer - 1) ;
break ;
case VK_DELETE:
// 该行字符自光标处起到最末的所有字符均前移一个
for (x = xCaret ; x < cxBuffer - 1 ; x++)
BUFFER (x, yCaret) = BUFFER (x + 1, yCaret) ;
// 清除方该行最后一个字符(此时它与前一个字符相同)
BUFFER (cxBuffer - 1, yCaret) = ' ' ;
//隐藏光标
HideCaret (hwnd) ;
hdc = GetDC (hwnd) ;
// 将等宽字体选入设备内容
SelectObject (hdc, CreateFont (0, 0, 0, 0, 0, 0, 0, 0,
/*dwCharSet*/0, 0, 0, 0,FIXED_PITCH, NULL)) ;
// 重新输出删除后的文字,cxBuffer - xCaret 全字串长度 - 起始位 = 字串长度
TextOut (hdc, xCaret * cxChar, yCaret * cyChar,
& BUFFER (xCaret, yCaret),
cxBuffer - xCaret) ;
DeleteObject (SelectObject (hdc, GetStockObject (SYSTEM_FONT))) ;
ReleaseDC (hwnd, hdc) ;
// 恢复光标
ShowCaret (hwnd) ;
break ;
}
SetCaretPos (xCaret * cxChar, yCaret * cyChar) ;
return 0 ;
case WM_CHAR:
for (i = 0 ; i < (int) LOWORD (lParam) ; i++) // lParam 低字节为重复计数
{
switch (wParam) // 由 wParam 参数获得字符代码
{
case '\b': // 退格键 backspace
if (xCaret > 0)
{
xCaret-- ;
SendMessage (hwnd, WM_KEYDOWN, VK_DELETE, 1) ;
}
break ;
case '\t': // tab 键
do
{
// 先执行再判断是否 8 的倍数,因此总能执行
SendMessage (hwnd, WM_CHAR, ' ', 1) ;
} while (xCaret % 8 != 0) ;
break ;
case '\n': // 换行
if (++yCaret == cyBuffer)// 如果一行满,则回到左边
yCaret = 0 ;
break ;
case '\r': // 回车
xCaret = 0 ;
if (++yCaret == cyBuffer) // 如果一屏满,则跳到首行
yCaret = 0 ;
break ;
case '\x1B': // Esc键,清空文本
for (y = 0 ; y < cyBuffer ; y++)
for (x = 0 ; x < cxBuffer ; x++)
BUFFER (x, y) = ' ' ;
xCaret = 0 ;
yCaret = 0 ;
InvalidateRect (hwnd, NULL, FALSE) ;
break ;
// 字符代码(上面是控制代码)
default:
// 得到字符代码
BUFFER (xCaret, yCaret) = (TCHAR) wParam ;
HideCaret (hwnd) ;
hdc = GetDC (hwnd) ;
// 创建逻辑字体
SelectObject (hdc, CreateFont (0, 0, 0, 0, 0, 0, 0, 0,
dwCharSet, 0, 0, 0, FIXED_PITCH, NULL)) ;
// 输出该字符
TextOut (hdc, xCaret * cxChar, yCaret * cyChar,
&BUFFER (xCaret, yCaret), 1) ;
DeleteObject ( SelectObject (hdc, GetStockObject (SYSTEM_FONT))) ;
ReleaseDC (hwnd, hdc) ;
ShowCaret (hwnd) ;
if (++xCaret == cxBuffer) // 如果一行满,换行
{
xCaret = 0 ;
if (++yCaret == cyBuffer) // 如果一屏满,则跳到首行
yCaret = 0 ;
}
break ;
}
}
// 重置光标位置
SetCaretPos (xCaret * cxChar, yCaret * cyChar) ;
return 0 ;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
SelectObject (hdc, CreateFont (0, 0, 0, 0, 0, 0, 0, 0,
dwCharSet, 0, 0, 0, FIXED_PITCH, NULL)) ;
// 输出所有字符
for (y = 0 ; y < cyBuffer ; y++)
TextOut (hdc, 0, y * cyChar, & BUFFER(0,y), cxBuffer) ;
DeleteObject (SelectObject (hdc, GetStockObject (SYSTEM_FONT))) ;
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
SetBkColor(hdc,RGB(100,100,100));
SetBkMode(hdc,0); // 设置字符显示为透明模式
SelectObject (hdc, CreateFont (0, 0, 0, 0, 0, 0, 0, 0,
dwCharSet, 0, 0, 0, FIXED_PITCH, NULL)) ;
// 输出所有字符
for (y = 0 ; y < cyBuffer ; y++)
TextOut (hdc, 0, y * cyChar, & BUFFER(0,y), cxBuffer) ;
DeleteObject (SelectObject (hdc, GetStockObject (SYSTEM_FONT))) ;
EndPaint (hwnd, &ps) ;
return 0 ;