大家知道,在使用微软的编程环境创建工程时会让你选择是控制台模式还是Windows应用程序。如果选择控制台的console模式,就会在运行时出现一个黑洞洞的字符模式窗口,里面就有等待输入一闪一闪的插入符。输入光标从DOS时代就存在,但是在Win32中赋予了更强大的功能。下图就是Windows的CMD窗口,其中的输入点就是插入光标:
要注意的是这里的插入符或插入光标并不是Windows中另外一个“光标”,这里是指示插入字符的位置,而不是用于鼠标,手写输入等可以定位、移动的光标(Cursor),而是插入符Caret,本文也成为插入光标,注意插入二字,为了方便,以下在本文中也简称为光标或插入符,但要注意此光标非彼光标。
为什么会有插入光标(插入符)?了解了这个基本问题,就成功了一半了。我们知道计算机可以通过键盘来输入各种字符和控制符,那么自然就存在一个问题,输入的字符应该放到屏幕的什么位置?这个就是光标产生的原因,光标实际上就是一个字符插入标识。简单的说就是我们想把字符输入到哪个位置,就先把插入符设置到那里,设置时其实就是告诉电脑输入的字符你给我在哪里显示!从这个我们也可以推断,插入符在同一时刻只能有一个。
- 光标相关API函数
要使用光标,首先得创建一个光标,创建光标的API函数为:
1 |
BOOL CreateCaret(HWND hWnd, HBITMAP hBitmap, int nWidth, int nHeight); |
hWnd参数表示光标是属于哪个窗口。
hBitmap参数是一个位图的句柄,计算机将使用这个句柄的位图来作为光标的形状。
既然光标是给使用电脑的人插入字符用的,那就得有形状让使用者能看到,因此光标需要有一个可见的小图标。当然为了不同的情况和需求,Windows让我们可以自定义光标的形状。常见的位图创建或者加载API函数如CreateBitmap、CreateDIBitmap、LoadBitmap等都可以创建或加载一个位图,将句柄作为该参数。
nWidth和nHeight分别是位图的宽和高。
光标创建之后是不会自动显示的,也就是默认是隐藏状态,需要主动调用下面的显示函数:
1 |
BOOL ShowCaret(HWND hWnd); |
当然有显示光标也可以隐藏光标:
1 |
BOOL HideCaret(HWND hWnd); |
以上两个函数的参数很简单,都是要显示窗口的句柄。
要设置插入符的位置,使用下面API函数:
1 |
BOOL SetCaretPos(int X, int Y); |
参数X、Y分别是相对于窗口客户区的坐标。
我们可以用如下API函数获取当前光标的位置:
1 |
BOOL GetCaretPos(LPPOINT lpPoint); |
参数lpPoint返回当前光标所在的位置。
我们知道光标会闪烁,这个闪烁的时间间隔是可以设置的,我们可以用如下API来设置和获取插入光标的闪烁时间:
1 2 |
BOOL SetCaretBlinkTime(UINT uMSeconds); UINT GetCaretBlinkTime(VOID); |
参数uMSeconds为闪烁的间隔毫秒数。
最后不再使用时需要销毁光标:
1 |
BOOL DestroyCaret(VOID); |
- 光标处理相关消息
与插入光标相关的消息主要有WM_SETFOCUS、WM_KILLFOCUS。通常在WM_SETFOCUS中创建和显示光标,而在WM_KILLFOCUS中销毁光标。一般应有中再结合WM_KEYDOWN和WM_CHAR消息,实现文本的输入。
- 光标应用实例
以下是一个简单的虚拟终端,我们常见的很多终端软件都是这样来实现的,比如常见的SecureCRT、Tera Term、XShell、putty等等。本实例就是用了插入光标来实现字符输入、插入,完整实例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
#include <windows.h> static TCHAR szWinName[] = TEXT("VirtualTerminal"); #define TEXTMATRIX(x, y) *(pTextMatrix + ((y) * nLineChars) + (x)) static TEXTMETRIC tm; //metric dimention of virtual terminal static TCHAR *pTextMatrix; //VT character buffer static int nCharWidth, nCharHeight; //the width and height of characeters static int nCaretPosX, nCaretPosY; //the current position of caret static int nVTWidth, nVTHeight; //the width and height of virtual terminal window static int nLineChars, nRowChars; //character number in one line and row static int nCaretOffsetY; //the offset of vertical height static COLORREF TextColor; //text color for terminal window, that is fore color static LRESULT CALLBACK VTWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); HWND CreateVirtualTerminal(HWND hWndParent, int left, int top, int width, int height, int id) { HWND hWnd; WNDCLASS wndclass; HINSTANCE hInst = GetModuleHandle(NULL); wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = VTWndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInst; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szWinName; if (!RegisterClass(&wndclass)) { return 0; } hWnd = CreateWindowEx(0, szWinName, NULL, WS_CHILD|WS_VISIBLE, left, top, width, height, hWndParent, (HMENU)id, hInst, NULL); return hWnd; } static void DrawChar(HDC hDC, int x, int y, TCHAR *str, int num) { RECT rect; SelectObject(hDC, GetStockObject(SYSTEM_FIXED_FONT)); SetTextColor(hDC, TextColor); SetBkMode(hDC, TRANSPARENT); rect.left = x; rect.top = y; rect.right = x + num * nCharWidth; rect.bottom = y + nCharHeight; FillRect(hDC, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH)); TextOut(hDC, nCaretPosX * nCharWidth, nCaretPosY * nCharHeight, &TEXTMATRIX(nCaretPosX, nCaretPosY), nLineChars - nCaretPosX); } static LRESULT CALLBACK VTWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int x, y; HDC hDC; switch (message) { case WM_CREATE: hDC = GetDC(hWnd); SelectObject(hDC, GetStockObject(SYSTEM_FIXED_FONT)); GetTextMetrics(hDC, &tm); ReleaseDC(hWnd, hDC); nCharWidth = tm.tmAveCharWidth; nCharHeight = tm.tmHeight; TextColor = RGB(255, 255, 255); nCaretOffsetY = 12; return 0; case WM_SIZE: nVTWidth = LOWORD(lParam); nLineChars = max(1, nVTWidth/nCharWidth); nVTHeight = HIWORD(lParam); nRowChars = max(1, nVTHeight/nCharHeight); if (pTextMatrix != NULL) { free(pTextMatrix); } pTextMatrix = (TCHAR *)malloc(nLineChars * nRowChars); if (pTextMatrix) { for (y=0; y<nRowChars; y++) { for (x=0; x<nLineChars; x++) { TEXTMATRIX(x, y) = TEXT(' '); } } } SetCaretPos(0, nCaretOffsetY); return 0; case WM_LBUTTONDOWN: SetFocus(hWnd); break; case WM_KEYDOWN: switch (wParam) { case VK_HOME: // Home nCaretPosX = 0; break; case VK_END: // End nCaretPosX = nLineChars - 1; break; case VK_PRIOR: // Page Up nCaretPosY = 0; break; case VK_NEXT: // Page Down nCaretPosY = nRowChars -1; break; case VK_LEFT: // Left arrow nCaretPosX = max(nCaretPosX - 1, 0); break; case VK_RIGHT: // Right arrow nCaretPosX = min(nCaretPosX + 1, nLineChars - 1); break; case VK_UP: // Up arrow nCaretPosY = max(nCaretPosY - 1, 0); break; case VK_DOWN: // Down arrow nCaretPosY = min(nCaretPosY + 1, nRowChars - 1); break; case VK_DELETE: // Delete // Move all the characters that followed the // deleted character (on the same line) one // space back (to the left) in the matrix. for (x = nCaretPosX; x < nLineChars; x++) TEXTMATRIX(x, nCaretPosY) = TEXTMATRIX(x + 1, nCaretPosY); // Replace the last character on the // line with a space. TEXTMATRIX(nLineChars - 1, nCaretPosY) = ' '; // The application will draw outside the // WM_PAINT message processing, so hide the caret. HideCaret(hWnd); // Redraw the line, adjusted for the // deleted character. hDC = GetDC(hWnd); DrawChar(hDC, nCaretPosX * nCharWidth, nCaretPosY * nCharHeight, &TEXTMATRIX(nCaretPosX, nCaretPosY), nLineChars - nCaretPosX/nCharWidth); ReleaseDC(hWnd, hDC); // Display the caret. ShowCaret(hWnd); break; } // Adjust the caret position based on the // virtual-key processing. SetCaretPos(nCaretPosX * nCharWidth, nCaretPosY * nCharHeight + nCaretOffsetY); return 0; case WM_SHOWWINDOW: SetFocus(hWnd); break; case WM_SETFOCUS: CreateCaret(hWnd, NULL, nCharWidth, 2); SetCaretPos(nCaretPosX * nCharWidth, nCaretPosY * nCharHeight + nCaretOffsetY); ShowCaret(hWnd); break; case WM_KILLFOCUS: case WM_DESTROY: HideCaret(hWnd); DestroyCaret(); break; case WM_CHAR: switch (wParam) { case 0x08: //process a backspace. if (nCaretPosX > 0) { nCaretPosX--; SendMessage(hWnd, WM_KEYDOWN, VK_DELETE, 1L); } break; case 0x09: //process a tab. do { SendMessage(hWnd, WM_CHAR, TEXT(' '), 2L); } while (nCaretPosX % 4 != 0); break; case 0x0D: //process a carriage return. nCaretPosX = 0; if (++nCaretPosY == nRowChars) { nCaretPosY = 0; } break; case 0x1B: case 0x0A: //process a linefeed. MessageBeep((UINT)-1); break; default: TEXTMATRIX(nCaretPosX, nCaretPosY) = (TCHAR)wParam; HideCaret(hWnd); hDC = GetDC(hWnd); DrawChar(hDC, nCaretPosX * nCharWidth, nCaretPosY * nCharHeight, &TEXTMATRIX(nCaretPosX, nCaretPosY), 1); ReleaseDC(hWnd, hDC); ShowCaret(hWnd); if (++nCaretPosX == nLineChars) { nCaretPosX = 0; if (++nCaretPosY == nRowChars) { nCaretPosY = 0; } } break; } SetCaretPos(nCaretPosX * nCharWidth, nCaretPosY * nCharHeight + nCaretOffsetY); return 0; case WM_PAINT: { PAINTSTRUCT ps; hDC = BeginPaint(hWnd, &ps); SelectObject(hDC, GetStockObject(SYSTEM_FIXED_FONT)); SetBkMode(hDC, TRANSPARENT); SetTextColor(hDC, TextColor); for (y=0; y<nLineChars; y++) { TextOut(hDC, 0, y * nCharHeight, &TEXTMATRIX(0, y), nLineChars); } EndPaint(hWnd, &ps); } return 0; default: break; } return DefWindowProc (hWnd, message, wParam, lParam); } |
下面是主程序文件,该文件调用上面的CreateVirtualTerminal函数来创建一个窗口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
#include <windows.h> #define IDC_VTID 9876 static TCHAR szAppName[] = TEXT("Caret demo"); static LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); extern HWND CreateVirtualTerminal(HWND hWndParent, int left, int top, int width, int height, int id); 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 szAppName, // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position 400, // initial x size 300, // 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; } static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hDC; PAINTSTRUCT ps; switch (message) { case WM_CREATE: CreateVirtualTerminal(hWnd, 10, 10, 360, 240, IDC_VTID); return 0; case WM_PAINT: hDC = BeginPaint(hWnd, &ps); ; EndPaint(hWnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0 ; } return DefWindowProc (hWnd, message, wParam, lParam); } |
示例程序运行后,在窗口中输入部分文本(模仿上面的cmd窗口^_^),效果如下:
本例实现了一个简单的终端模拟小程序,为了读者重用方便,我将终端模拟的小窗口单独作为一个完整的源文件,并且把窗口背景设为黑色,前景色设为白色,看起来更像CMD、Linux等命令行窗口。
更多经验交流可以加入Windows编程讨论QQ群:454398517。
关注微信公众平台:程序员互动联盟(coder_online),你可以第一时间获取原创技术文章,和(java/C/C++/Android/Windows/Linux)技术大牛做朋友,在线交流编程经验,获取编程基础知识,解决编程问题。程序员互动联盟,开发人员自己的家。
转载请注明出处http://www.coderonline.net/?p=1905,谢谢合作!
本文原始地址:http://www.coderonline.net/programming-windows-series-the-tenth-article-insert-text-break.html
本站所有文章,除特别注明外,均为本站原创,转载请注明出处来自http://www.coderonline.net/
否则保留追究法律责任的权利!
求婚视频|婚礼 http://www.5aivideo.com 视频|婚礼跟拍|婚礼微电影|婚礼现场视频|婚礼MV|婚礼摄影|婚礼摄像婚礼mv视频|婚礼视频制作|婚礼高清摄像|婚礼跟拍作品|婚礼跟拍价格|婚礼跟拍摄影婚礼跟拍录像|婚礼跟拍摄像师|婚礼跟拍多少钱|最感人的婚礼视频|婚礼视频mv短片制作婚礼摄影师|婚礼摄影跟拍价格|婚礼摄影一般多少钱|婚礼摄影师一场多少钱|豪华婚礼mv婚礼mv|婚礼花絮mv|婚礼视频mv短片|婚礼上播放的mv视频|最浪漫感人的婚礼视频结婚mv创意视频短片|婚礼创意mv婚礼上播放|婚礼摄像师|婚礼摄像价格|婚礼高清摄像婚礼摄像团队|婚礼摄像跟拍|婚礼摄影摄像哪个重要|婚礼微电影制作|婚礼微电影机构国外婚礼微电影|婚
宣传片制作|企业宣传片|企业宣 http://www.d2film.com 传片拍摄|企业宣传片制作|影视制作公司|宣传片拍摄哪家强视频制作公司|企业宣传片文案|宣传片拍摄公司|宣传片制作公司|宣传片制作公司企业宣传片报价|影视制作价格|公司宣传片制作|企业视频制作|企业宣传片制作公司企业宣传片制作公司|公司宣传片拍摄|产品宣传片拍摄|企业宣传片策划|影视制作报价影视制作团队|影视制作哪家好|视频制作团队|视频制作费用|视频制作价格|宣传片拍摄报价单视频制作哪家拍的好|企业拍宣传片|大企业宣传片|企业宣传片怎么做|企业宣传片制作报价企业宣传片制作价格|企业宣传片拍摄公司|企业宣传片创意视频|企业宣传片制作哪家好5分钟宣传片一般多少钱|企业
宣传片制作|企业宣传片|企业宣传片拍摄|企业宣传片制作|影视制作公 http://www.d2film.com 司|宣传片拍摄哪家强视频制作公司|企业宣传片文案|宣传片拍摄公司|宣传片制作公司|宣传片制作公司企业宣传片报价|影视制作价格|公司宣传片制作|企业视频制作|企业宣传片制作公司企业宣传片制作公司|公司宣传片拍摄|产品宣传片拍摄|企业宣传片策划|影视制作报价影视制作团队|影视制作哪家好|视频制作团队|视频制作费用|视频制作价格|宣传片拍摄报价单视频制作哪家拍的好|企业拍宣传片|大企业宣传片|企业宣传片怎么做|企业宣传片制作报价企业宣传片制作价格|企业宣传片拍摄公司|企业宣传片创意视频|企业宣传片制作哪家好5分钟宣传片一般多少钱|企业
宣传片制作|企业宣传片|企业宣传片拍摄|企业宣传片制作|影视制作公司|宣传片拍摄哪家强视频制作公司|企业 http://www.d2film.com 宣传片文案|宣传片拍摄公司|宣传片制作公司|宣传片制作公司企业宣传片报价|影视制作价格|公司宣传片制作|企业视频制作|企业宣传片制作公司企业宣传片制作公司|公司宣传片拍摄|产品宣传片拍摄|企业宣传片策划|影视制作报价影视制作团队|影视制作哪家好|视频制作团队|视频制作费用|视频制作价格|宣传片拍摄报价单视频制作哪家拍的好|企业拍宣传片|大企业宣传片|企业宣传片怎么做|企业宣传片制作报价企业宣传片制作价格|企业宣传片拍摄公司|企业宣传片创意视频|企业宣传片制作哪家好5分钟宣传片一般多少钱|企业
求婚视频|婚礼视频|婚礼跟拍|婚礼微电影|婚礼现场视频|婚礼MV|婚礼摄影|婚礼摄像 http://www.5aivideo.com 婚礼mv视频|婚礼视频制作|婚礼高清摄像|婚礼跟拍作品|婚礼跟拍价格|婚礼跟拍摄影婚礼跟拍录像|婚礼跟拍摄像师|婚礼跟拍多少钱|最感人的婚礼视频|婚礼视频mv短片制作婚礼摄影师|婚礼摄影跟拍价格|婚礼摄影一般多少钱|婚礼摄影师一场多少钱|豪华婚礼mv婚礼mv|婚礼花絮mv|婚礼视频mv短片|婚礼上播放的mv视频|最浪漫感人的婚礼视频结婚mv创意视频短片|婚礼创意mv婚礼上播放|婚礼摄像师|婚礼摄像价格|婚礼高清摄像婚礼摄像团队|婚礼摄像跟拍|婚礼摄影摄像哪个重要|婚礼微电影制作|婚礼微电影机构国外婚礼微电影|婚
“我没招惹她,自己贴上来的,唉,不说了,兄弟心里苦啊。”欧阳傲枫作怪的叫了一声,举杯喝了一口,把杯子往桌上一扔,大声道:“我来一首。”
视频制作哪家拍的好_企业拍宣传片_大企业宣传片_企业宣传片怎么做_企业宣传片制作报价影视视频制作d2film.com企业宣传片制作拍摄QQ30998
企业宣传片制作d2film.com影视视频制作公司QQ30998 http://www.d2film.com/
国外婚礼微电影_婚礼微电影价格_婚礼微电影视频_婚礼微电影拍摄_婚礼微电影创意婚礼摄影MV-5aivideo.com婚礼摄像微电影QQ73595
婚礼摄影MV-5aivideo.com婚礼摄像微电影QQ73595 http://www.5aivideo.com/
谢谢博主