1 #include <windows.h> 2 3 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);//回调函数 WndProc; 4 5 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) 6 { 7 8 WNDCLASS wndclass;//窗口类 9 static TCHAR szWindowsName[]=TEXT("MyWindows"),szClassName[] = TEXT("MyClass"); 10 HWND hWnd; 11 MSG msg; 12 13 //设置类风格 14 wndclass.style = CS_VREDRAW | CS_HREDRAW; 15 wndclass.cbClsExtra = 0; 16 wndclass.cbWndExtra = 0; 17 wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 18 wndclass.hCursor = LoadCursor(NULL, IDC_HAND); 19 wndclass.hIcon = LoadIcon(NULL, IDI_ERROR); 20 wndclass.hInstance = hInstance; 21 wndclass.lpfnWndProc = WndProc; 22 wndclass.lpszClassName = szClassName; 23 wndclass.lpszMenuName = NULL; 24 25 //注册窗口类 26 RegisterClass(&wndclass); 27 28 //生成窗口 29 hWnd=CreateWindow(szClassName, szWindowsName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 30 NULL, NULL, hInstance, NULL); 31 32 UpdateWindow(hWnd);//更新窗口 33 ShowWindow(hWnd, iCmdShow);//显示窗口 34 35 //消息循环 36 while (GetMessage(&msg, NULL, NULL, NULL)) 37 { 38 TranslateMessage(&msg);//翻译键盘消息 39 DispatchMessage(&msg);//转发消息到WnProc 40 } 41 return msg.wParam; 42 } 43 44 LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 45 { 46 static int cxClientMax, cyClientMax, cxClient, cyClient, cxChar, cyChar; 47 static int cLinesMax, cLines; 48 static PMSG pmsg; 49 static RECT rectScroll; 50 static TCHAR szTop[] = TEXT("Message Key Char Repeat Scan Ext ALT Prev Tran"); 51 static TCHAR szUnd[] = TEXT("_______ ___ ____ ______ ____ ___ ___ ____ ____"); 52 static TCHAR * szFormat[2] = { 53 TEXT("%-13s %3d%-15s%c%6u%4d%3s%3s%4s%4s"), 54 TEXT("%-13s 0x%04X%1s%c%6u%4d%3s%3s%4s%4s")}; 55 static TCHAR *szYes = TEXT("Yes"); 56 static TCHAR *szNo = TEXT("No"); 57 static TCHAR *szDown = TEXT("Down"); 58 static TCHAR *szUp = TEXT("Up"); 59 static TCHAR *szMessage[] = { 60 TEXT("WM_KEYDOWN"),TEXT("WM_KEYUP"), 61 TEXT("WM_CHAR"),TEXT("WM_DEADCHAR"), 62 TEXT("WM_SYSKEYDOWN"),TEXT("WM_SYSKEYUP"), 63 TEXT("WM_SYSCHAR"),TEXT("WM_SYSDEADCHAR") 64 }; 65 int i, iType; 66 TCHAR szBuffer[128], szKeyName[32]; 67 TEXTMETRIC tm; 68 PAINTSTRUCT ps; 69 HDC hdc; 70 71 switch (msg) 72 { 73 //WM_CREATE 和 WM_DISPLAYCHANGE 消息共同执行下面代码 74 case WM_CREATE: 75 case WM_DISPLAYCHANGE: 76 //获取 客户端最大宽度 77 cxClientMax = GetSystemMetrics(SM_CXMAXIMIZED); 78 //获取 客户端最大高度 79 cyClientMax = GetSystemMetrics(SM_CYMAXIMIZED); 80 81 hdc = GetDC(hWnd); 82 //设置当前hdc为等款字体 83 SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT)); 84 //获取 文本信息 85 GetTextMetrics(hdc, &tm); 86 //设置字符宽度 87 cxChar = tm.tmAveCharWidth; 88 //设置字符高度 89 cyChar = tm.tmHeight; 90 ReleaseDC(hWnd, hdc); 91 92 93 if (pmsg)//如果没有东西 94 { 95 free(pmsg);//释放pmsg 96 } 97 98 99 //获取 客户端 最大容量行数 客户端最大高度/字符高度 100 cLinesMax = cyClientMax / cyChar; 101 //生成 内存中 取 MSG 大小的内存 * 客户端最大行数 102 pmsg =(PMSG) malloc(cLinesMax * sizeof(MSG)); 103 // 清空当前行数 104 cLines = 0; 105 106 //继续执行 107 case WM_SIZE: 108 //如果是 WM_SIZE消息 109 if (msg == WM_SIZE) 110 { 111 //获取 客户端宽度 112 cxClient = LOWORD(lParam); 113 //获取 客户端高度 114 cyClient = HIWORD(lParam); 115 } 116 //设置 矩形 左边为 0 117 rectScroll.left = 0; 118 //设置 矩形 右边为 最大客户端宽度 119 rectScroll.right = cxClient; 120 //设置 矩形 顶边 为 字符高度。 因为最上面有 我们的 字符 121 rectScroll.top = cyChar; 122 //设置 矩形 底边 为 字符高度*(客户端高度 /字符高度) 其实没必要 直接 cyClient。书上这样写我不知道为啥 123 rectScroll.bottom = cyChar*(cyClient / cyChar); 124 125 //失效矩形区域 重画 126 InvalidateRect(hWnd, NULL, TRUE); 127 return 0;//这里返回 128 129 //下面全部是键盘消息 130 case WM_KEYDOWN: 131 case WM_KEYUP: 132 case WM_CHAR: 133 case WM_DEADCHAR: 134 case WM_SYSKEYDOWN: 135 case WM_SYSKEYUP: 136 case WM_SYSCHAR: 137 case WM_SYSDEADCHAR: 138 139 //i=客户端最大行数-1 。如果 i>0 那么就 滚动消息 140 for (i = cLinesMax - 1; i > 0; i--) 141 { 142 //滚动消息。 143 pmsg[i] = pmsg[i - 1]; 144 } 145 pmsg[0].hwnd = hWnd; 146 pmsg[0].message = msg; 147 pmsg[0].wParam = wParam; 148 pmsg[0].lParam = lParam; 149 //消息 最下面的赋值最新 150 /* 151 比如: 当前 最大行数为 100 152 i=99; i如果大于 0 153 那么 pmsg[99]=pmsg[98]...... 154 pmsg[1]=pmsg[0]; 这时 i=0 取消循环 155 由 WM_PAIN 来重绘 窗口显示内容 156 但是 记住 这里 不管里面有没有消息都是 滚动的。 157 */ 158 159 //下面代码 看起来是 防止 超出内容 其实 是每次累加 cLines的值 160 cLines = min(cLines + 1, cLinesMax); 161 162 //滚动 矩形区域。以负数形式 向上翻滚 每次翻滚 一个字符高度。 163 ScrollWindow(hWnd, 0, -cyChar, &rectScroll, &rectScroll); 164 break;//跳出 选择 165 case WM_PAINT: 166 hdc=BeginPaint(hWnd, &ps); 167 //设置 字体为等宽字体 168 SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT)); 169 //设置字体为 透明模式 170 SetBkMode(hdc, TRANSPARENT); 171 //画出两行可以叠加的文字 172 TextOut(hdc, 0, 0, szTop, lstrlen(szTop)); 173 TextOut(hdc, 0, 0, szUnd, lstrlen(szUnd)); 174 175 //i=0; i 小于 (当前行数,客户端高度/字符高度-1) 176 // 这里的 意思是 如果行数 是 5 在如果 高度为100 字符高度为5 177 //那么 100/5=20 20-1 =19 19是最大能容量的字符个数 如果 前者大于后者 那么 永远 是 19了。 178 for (i = 0; i < min(cLines, cyClient / cyChar - 1); i++) 179 { 180 181 // 如果 消息[i]的消息是 以下这几个 就赋值 真 否则 为假; 182 iType = pmsg[i].message == WM_CHAR || 183 pmsg[i].message == WM_SYSCHAR || 184 pmsg[i].message == WM_DEADCHAR || 185 pmsg[i].message == WM_SYSDEADCHAR; 186 187 //获取 键的 名字文本 。用lParam作为参数 放到szKeyName 第三参数意思为 100/5 =20; 188 GetKeyNameText(pmsg[i].lParam, szKeyName, sizeof(szKeyName) / sizeof(TCHAR)); 189 190 //输出文本 左边为0 顶边为 计算过后的 (客户高度/字符高度-1-i)*字符高度; 191 //比如: 客户高度:100 字符高度:5 192 // 100/5-1 =19 -i 这个i 就是 已经画过了的。为什么最后*cyChar。 因为 这是高度。 193 //画的文本是 szBuffer里面的。但是 现在 szBuffer貌似没有值。 194 // 接下来一个参数 用wsprintf 格式化字符串 到szBuffer里面。iType标记了第几个数组。 195 //szMessage[pmsg[i].message - WM_KEYFIRST], 196 //意思是第i个消息收到之后 减去 标准消息 为的是方便数组的选取 197 //(PTSTR)(iType ? TEXT(" ") : szKeyName),//判断是否为键消息 198 //(TCHAR)(iType ? pmsg[i].wParam : ‘ ‘),//判断是否为字符消息 199 /* 200 LOWORD(pmsg[i].lParam), HIWORD(pmsg[i].lParam) & 0xFF, 201 0x01000000 & pmsg[i].lParam ? szYes : szNo, 202 0x20000000 & pmsg[i].lParam ? szYes : szNo, 203 0x40000000 & pmsg[i].lParam ? szDown : szUp, 204 0x80000000 & pmsg[i].lParam ? szUp : szDown)); 205 以上几句话 对照 键盘的参数 来得出答案。分别是获取 键或者字符的附加参数 206 */ 207 TextOut(hdc, 0, (cyClient / cyChar - 1 - i) * cyChar, szBuffer, 208 wsprintf(szBuffer, szFormat[iType], 209 szMessage[pmsg[i].message - WM_KEYFIRST], pmsg[i].wParam, 210 (PTSTR)(iType ? TEXT(" ") : szKeyName), 211 (TCHAR)(iType ? pmsg[i].wParam : ‘ ‘), 212 LOWORD(pmsg[i].lParam), HIWORD(pmsg[i].lParam) & 0xFF, 213 0x01000000 & pmsg[i].lParam ? szYes : szNo, 214 0x20000000 & pmsg[i].lParam ? szYes : szNo, 215 0x40000000 & pmsg[i].lParam ? szDown : szUp, 216 0x80000000 & pmsg[i].lParam ? szUp : szDown)); 217 } 218 219 //TextOut(hdc, 0, 0, TEXT("这是一个标准的C语言Windows窗口."), lstrlen(TEXT("这是一个标准的C语言Windows窗口."))); 220 221 EndPaint(hWnd, &ps); 222 return 0; 223 case WM_DESTROY: 224 PostQuitMessage(0); 225 return 0; 226 } 227 return DefWindowProc(hWnd, msg, wParam, lParam); 228 }
时间: 2024-11-06 05:08:27