在许多文本编辑器中,列选择功能是一个非常有用的特性,它允许用户通过按住Alt键并拖动鼠标来选择文本列。尽管这种功能在诸如Visual Studio等应用程序中很常见,但实现它并不总是那么直观。本文将介绍如何在项目中实现列选择功能,并提供一些示例图片来展示这一功能在其他应用程序中的实现方式。
实现列选择的策略相对简单,主要包括以下几个步骤:
以下是实现列选择功能的一些关键代码段:
1. 在CColBasedRichEdit类中实现了这个功能,该类继承自MFC的CRichEditCtrl。
m_processedDC = ::CreateCompatibleDC(NULL);
HBITMAP bmpREdit = ::CreateCompatibleBitmap(*pDC, rcClient.Width(), rcClient.Height());
::SelectObject(m_processedDC, bmpREdit);
2. 创建一个与当前屏幕兼容的内存DC,并创建一个与RichEdit控件兼容的位图。
COLORREF clrHilite = ::GetSysColor(COLOR_HIGHLIGHT);
HBRUSH brHilite = CreateSolidBrush(clrHilite);
::FillRect(m_processedDC, CRect(0, 0, rcClient.Width(), rcClient.Height()), brHilite);
3. 创建一个指定宽度和高度的位图,但其内容未定义(为NULL)。
CHBITMAP hMemBmp = CreateBitmap(rcClient.Width(), rcClient.Height(), 1, 1, NULL);
4. 将RichEdit的DC复制到m_hSelectionDC。
BitBlt(m_hSelectionDC, 0, 0, rcClient.Width(), rcClient.Height(), *pDC, 0, 0, SRCCOPY);
5. 现在,可以看到MERGEPAINT的魔力。
BitBlt(m_processedDC, 0, 0, rcClient.Width(), rcClient.Height(), m_hSelectionDC, 0, 0, MERGEPAINT);
首先,反转源DC的像素。其次,将m_processedDC与m_hSelectionDC的像素(逐像素)合并。
6. 现在,已经准备好了m_processedDC,可以开始使用了。
7. 在鼠标移动消息中,计算用户选择的起始点和结束点。
CPoint ptTemp = PosFromChar(CharFromPos(point));
ptTemp.x = ptTemp.x + m_FontWidth - 2;
ptTemp.y = ptTemp.y + m_FontHeight - 2;
if ((ptTemp.x > (m_colSelEndPt.x + 4)) || (ptTemp.x < (m_colSelEndPt.x - 4)) ||
(ptTemp.y > (m_colSelEndPt.y + 4)) || (ptTemp.y < (m_colSelEndPt.y - 4))) {
m_colSelEndPt = ptTemp;
Invalidate();
UpdateWindow();
}
8. 要复制选定的区域/文本,使用了MSDN的剪贴板概念,实际上分配了全局内存/共享内存。
hClipboardData = (HGLOBAL)GlobalAlloc(GMEM_DDESHARE, sizeText);
pszClipText = (LPTSTR)GlobalLock((HGLOBAL)hClipboardData);
SetClipboardData(CF_UNICODETEXT, hClipboardData);