【Windows编程】系列第十篇:文本插入符
大家知道,在使用微软的编程环境创建工程时会让你选择是控制台模式还是Windows应用程序。如果选择控制台的console模式,就会在运行时出现一个黑洞洞的字符模式窗口,里面就有等待输入一闪一闪的插入符。输入光标从DOS时代就存在,但是在Win32中赋予了更强大的功能。下图就是Windows的CMD窗口,其中的输入点就是插入光标:
要注意的是这里的插入符或插入光标并不是Windows中另外一个“光标”,这里是指示插入字符的位置,而不是用于鼠标,手写输入等可以定位、移动的光标(Cursor),而是插入符Caret,本文也成为插入光标,注意插入二字,为了方便,以下在本文中也简称为光标或插入符,但要注意此光标非彼光标。
为什么会有插入光标(插入符)?了解了这个基本问题,就成功了一半了。我们知道计算机可以通过键盘来输入各种字符和控制符,那么自然就存在一个问题,输入的字符应该放到屏幕的什么位置?这个就是光标产生的原因,光标实际上就是一个字符插入标识。简单的说就是我们想把字符输入到哪个位置,就先把插入符设置到那里,设置时其实就是告诉电脑输入的字符你给我在哪里显示!从这个我们也可以推断,插入符在同一时刻只能有一个。
- 光标相关API函数
要使用光标,首先得创建一个光标,创建光标的API函数为:
BOOL CreateCaret(HWND hWnd, HBITMAP hBitmap, int nWidth, int nHeight);
hWnd参数表示光标是属于哪个窗口。
hBitmap参数是一个位图的句柄,计算机将使用这个句柄的位图来作为光标的形状。
既然光标是给使用电脑的人插入字符用的,那就得有形状让使用者能看到,因此光标需要有一个可见的小图标。当然为了不同的情况和需求,Windows让我们可以自定义光标的形状。常见的位图创建或者加载API函数如CreateBitmap、CreateDIBitmap、LoadBitmap等都可以创建或加载一个位图,将句柄作为该参数。
nWidth和nHeight分别是位图的宽和高。
光标创建之后是不会自动显示的,也就是默认是隐藏状态,需要主动调用下面的显示函数:
BOOL ShowCaret(HWND hWnd);
当然有显示光标也可以隐藏光标:
BOOL HideCaret(HWND hWnd);
以上两个函数的参数很简单,都是要显示窗口的句柄。
要设置插入符的位置,使用下面API函数:
BOOL SetCaretPos(int X, int Y);
参数X、Y分别是相对于窗口客户区的坐标。
我们可以用如下API函数获取当前光标的位置:
BOOL GetCaretPos(LPPOINT lpPoint);
参数lpPoint返回当前光标所在的位置。
我们知道光标会闪烁,这个闪烁的时间间隔是可以设置的,我们可以用如下API来设置和获取插入光标的闪烁时间:
BOOL SetCaretBlinkTime(UINT uMSeconds);
UINT GetCaretBlinkTime(VOID);
参数uMSeconds为闪烁的间隔毫秒数。
最后不再使用时需要销毁光标:
BOOL DestroyCaret(VOID);
- 光标处理相关消息
与插入光标相关的消息主要有WM_SETFOCUS、WM_KILLFOCUS。通常在WM_SETFOCUS中创建和显示光标,而在WM_KILLFOCUS中销毁光标。一般应有中再结合WM_KEYDOWN和WM_CHAR消息,实现文本的输入。
- 光标应用实例
以下是一个简单的虚拟终端,我们常见的很多终端软件都是这样来实现的,比如常见的SecureCRT、Tera Term、XShell、putty等等。本实例就是用了插入光标来实现字符输入、插入,完整实例代码如下:
#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函数来创建一个窗口。
#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,谢谢合作!
【Windows编程】系列第十篇:文本插入符的更多相关文章
- 《windows核心编程系列》十九谈谈使用远程线程来注入DLL。
windows内的各个进程有各自的地址空间.它们相互独立互不干扰保证了系统的安全性.但是windows也为调试器或是其他工具设计了一些函数,这些函数可以让一个进程对另一个进程进行操作.虽然他们是为调试 ...
- 《windows核心编程系列》十八谈谈windows钩子
windows应用程序是基于消息驱动的.各种应用程序对各种消息作出响应从而实现各种功能. windows钩子是windows消息处理机制的一个监视点,通过安装钩子能够达到监视指定窗体某种类型的消息的功 ...
- java并发编程JUC第十篇:CyclicBarrier线程同步
在之前的文章中已经为大家介绍了java并发编程的工具:BlockingQueue接口.ArrayBlockingQueue.DelayQueue.LinkedBlockingQueue.Priorit ...
- 走进windows编程的世界-----入门篇
1 Windows编程基础 1.1Win32应用程序基本类型 1) 控制台程序 不须要完好的windows窗体,能够使用DOS窗体方式显示 2) Win32窗体程序 包括窗体的程序,能够通过窗 ...
- 《windows核心编程系列》十六谈谈内存映射文件
内存映射文件允许开发人员预订一块地址空间并为该区域调拨物理存储器,与虚拟内存不同的是,内存映射文件的物理存储器来自磁盘中的文件,而非系统的页交换文件.将文件映射到内存中后,我们就可以在内存中操作他们了 ...
- 《windows核心编程系列》十五谈谈windows线程栈
谈谈windows线程栈. 当系统创建线程时会为线程预订一块地址空间区域,注意仅仅是预订.默认情况下预定的这块区域的大小是1MB,虽然预订这么多,但是系统并不会给全部区域调拨物理存储器.默认情况下,仅 ...
- 《Windows核心编程系列》十四谈谈默认堆和自定义堆
堆 前面我们说过堆非常适合分配大量的小型数据.使用堆可以让程序员专心解决手头的问题,而不必理会分配粒度和页面边界之类的事情.因此堆是管理链表和数的最佳方式.但是堆进行内存分配和释放时的速度比其他方式都 ...
- 《Windows核心编程系列》十二谈谈Windows内存体系结构
Windows内存体系结构 理解Windows内存体系结构是每一个励志成为优秀的Windows程序员所必须的. 进程虚拟地址空间 每个进程都有自己的虚拟地址空间.对于32位操作系统来说,它的地址空间是 ...
- [C# 网络编程系列]专题十:实现简单的邮件收发器
转自:http://www.cnblogs.com/zhili/archive/2012/09/24/2689892.html 引言: 在我们的平常工作中,邮件的发送和接收应该是我们经常要使用到的功能 ...
随机推荐
- Effective java笔记(七),通用程序设计
45.将局部变量的作用域最小化 将局部变量的作用域最小化,可以增强代码的可读性和可维护性,并降低出错的可能性. Java允许在任何可以出现语句的地方声明变量(C语言中局部变量要在代码块开头声明),要使 ...
- 通过Canvas + JS 实现简易时钟实战
最近通过各种渠道学习了下html5中的canvas元素,为了练练手就随手写了一个简易的时钟.时钟本身不复杂,没有使用图片进行美化,下面就与大家分享一下具体的代码: 这是最终实现的效果: 部分的启发点来 ...
- 在 .NET 中远程请求 https 内容时,发生错误:根据验证过程,远程证书无效。
当访问 https 内容的时候,有时候经常会看到证书错误(不在操作系统的证书信任链中?)的提示,在浏览器中我们可以忽略错误的证书,继续访问网页内容. 但是在 .NET 程序中,需要由代码来判断是否忽略 ...
- securityPolicy与安全策略等级配置
securityPolicy配置节是定义一个安全策略文件与其信任级别名称之间的映射的集合.配置如下所示 其中name是指定映射到策略文件的命名的安全级别,一般的值有Full,Hight,Medium, ...
- 纯css3艺术文字样式效果代码
效果:http://hovertree.com/texiao/css3/1/ 本效果主要使用text-shadow实现.参考:http://hovertree.com/h/bjaf/css3_text ...
- sql 中的Bulk和C# 中的SqlBulkCopy批量插入数据 ( 回顾 and 粗谈 )
通常,我们会对于一个文本文件数据导入到数据库中,不多说,上代码. 首先,表结构如下. 其次,在我当前D盘中有个文本文件名为2.txt的文件. 在数据库中,可以这样通过一句代码插入. Bulk in ...
- php strtotime 在32位操作系统下的限制
php strtotime 在32位操作系统下的限制 <?php class DateHelper{ /** * 在32位操作系统下,超过 2038-01-19 03:14:07 ,会溢出 * ...
- windows phone 水印TextBox
原文来自:wp教程网 原理:在失去焦点和获取焦点的时候,判断Text值是否为空或者是否与水印值相同,然后修改TextBox中的Text和Foreground. 代码如下: /* =========== ...
- java web学习总结(十五) -------------------JSP基础语法
任何语言都有自己的语法,JAVA中有,JSP虽然是在JAVA上的一种应用,但是依然有其自己扩充的语法,而且在JSP中,所有的JAVA语句都可以使用. 一.JSP模版元素 JSP页面中的HTML内容称之 ...
- jquery.dataTable.js 基础配置
$(document).ready(function () { $('#dataTables-example').DataTable({ responsive: true, "bPagina ...