先概述一下,现在做一个项目,需要用一个windowless richedit 做一个文本框,然后实现文本框的编辑功能。由于某种原因,我需要将文本框的窗口设定为透明的。这样,就面对了一个问题,就是要在编辑状态下实现透明窗口光标的显示(以及其他功能,暂且不述),因为编辑状态如果连光标都无法显示编辑就无从谈起。现在所面对的问题是,我无法在透明窗口上显示光标。
下面详细的说一下问题的程序建立的步骤,我分析问题更多与透明窗口有关系,而与windowless richedit的关系不大,所以windowless richedit的建立和销毁等叙述会比较简单:
1 先建立一个MFC的对话框类,在该对话框类的构造函数中,获得windowless richedit中的ITextHost、ITextServices和ITextDocument指针。
2 在对话框的OnInitDialog()中,完成下列功能:
(1) 设定窗口layer属性,设定的代码如下:
SetWindowLong(this->m_hWnd, GWL_EXSTYLE, GetWindowLong(this->m_hWnd, GWL_EXSTYLE) | WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE);
通过上面的语句,将对话框窗口设定成了layer窗口。实现了透明效果。
(2)为windowless richedit添加文字。代码不表了。
3 在重绘函数OnPaint()中,用UpdateLayeredWindow将文本框的内容显示出来。步骤如下:
(1) 建立一个32位的bitmap位图,然后将其数据全部清零。(从而alpha值也为零了)
(2) 通过上面建立的bitmap位图,建立一个和对话框dc相兼容的hdc。
(3) 调用windowless richedit的绘制函数将文本框内容绘制到兼容hdc中。
(4) 用UpdateLayeredWindow函数将本文框框内容绘制到当前的对话框窗口中。
这段代码后面会给出。
4 在对话框中重写了virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);函数,目的是为了在对话框中,自己处理一些消息。处理的代码如下:
if ( (WM_MOUSEFIRST <= message && message <= WM_MOUSELAST) || (message == WM_SETFOCUS))
{
CreateSolidCaret (100, 100);
SetCaretPos (CPoint(120,60));
ShowCaret();
//delete pBitmap;
return CDialog::WindowProc(message, wParam,lParam);
}
else
return CDialog::WindowProc(message, wParam,lParam);
代码写的不太好,就是测试代码,这个代码完成的功能是:如果是与鼠标相关的消息或者是激活消息。则通过MFC封装函数建立光标,设定光标位置 并显示出来。
5 完成了以上几步后,我认为光标就应该在希望的位置显示了,然而遗憾的是,没有显示出来。但是在下面两种情况下,就可以显示。
1 不在将对话框设定为layer属性,也就是说,采用普通窗口,然后在调用windowless richedit框的绘制函数中,直接传入对话框的hdc,这时候,就可以正确的显示设定的光标。
2 如果在对话框的OnInitDialog()中,在指定windows的layer属性之后,添加 SetLayeredWindowAttributes(cKey.ToCOLORREF(), 150, LWA_ALPHA);这个语句,则可以显示光标。当然,参数不是唯一的,而且也不一定非得alpha模式,color key模式也可以显示光标。比如:SetLayeredWindowAttributes(cKey.ToCOLORREF(), 150, LWA_COLORKEY);
现在的疑问是:为什么不指定layer窗口,或者用SetLayeredWindowAttributes规范一下透明窗口,就可以将光标显示出来了?为什么用UpdateLayeredWindow就无法显示呢?
现在给出用UpdateLayeredWindow显示文本的代码。
void CRichDrawExampleDlg::OnPaintRectLayer(RectF& invalidateRect,CDC& dc )
{
CRect rct;
::GetWindowRect( m_hWnd, &rct );
BITMAPINFOHEADER bmih;
ZeroMemory( &bmih, sizeof( BITMAPINFOHEADER ) );
bmih.biSize = sizeof( BITMAPINFOHEADER );
bmih.biWidth = rct.Width();
bmih.biHeight = - rct.Height();
bmih.biPlanes = 1 ;
bmih.biBitCount = 32;//这里一定要是
bmih.biCompression = BI_RGB;
bmih.biSizeImage = 0 ;
bmih.biXPelsPerMeter = 0 ;
bmih.biYPelsPerMeter = 0 ;
bmih.biClrUsed = 0 ;
bmih.biClrImportant = 0 ;
int iBPP = GetDeviceCaps(dc.GetSafeHdc(), BITSPIXEL );
HDC hdcMemory1 = CreateCompatibleDC( dc.GetSafeHdc());
BYTE *dst = NULL;
HBITMAP hBitMap1 = CreateDIBSection(dc.GetSafeHdc(),( BITMAPINFO* )&bmih, DIB_RGB_COLORS, ( VOID** )&dst, NULL, 0 );
memset( dst, 0, rct.Height() * rct.Width() * 4 );
SelectObject( hdcMemory1, hBitMap1 );
CRect rect = RectFToCRect(invalidateRect);
m_RichText.DrawText(hdcMemory1,rect,this);
//if( iBPP != 32 )
{
HDC hdcMemory2 = CreateCompatibleDC( dc.GetSafeHdc() );
BYTE *dstW = NULL;
HBITMAP hBitMap2 = CreateDIBSection( dc.GetSafeHdc(), ( BITMAPINFO* )&bmih, DIB_RGB_COLORS, ( VOID** )&dstW, NULL, 0 );
memset( dstW, 254, rct.Height() * rct.Width() * 4 );
SelectObject( hdcMemory2, hBitMap2 );
m_RichText.DrawText(hdcMemory2,rect,this);
BYTE r, g, b, a, rw, gw, bw, aw, alpha_r, alpha_g, alpha_b, alpha;
for (int y = 0; y < rct.Height() ; y++)
{
for (int x = 0; x < rct.Width(); x++)
{
//the idea is that we draw the same data onto black and white DC's
//and then calculate per pixel alpha based on difference, produced by alpha blending
r = *dst++;
g = *dst++;
b = *dst++;
a = *dst++;
rw = *dstW++;
gw = *dstW++;
bw = *dstW++;
aw = *dstW++;
alpha_r = rw-r;
alpha_g = gw-g;
alpha_b = bw-b;
//division by 3 is for accuracy and can be replaced by
//alpha = alpha_g; for example
alpha = (alpha_r + alpha_g + alpha_b) / 3;
*(dst - 1) = 255 - alpha;
//this algorithm should be optimized for MMX to achieve best performance
}
}
DeleteObject( hBitMap2 );
DeleteDC( hdcMemory2 );
}
//for (int i = 0 ; i < rct.Height(); ++i)
//{
// for (int j = 0; j < rct.Width(); ++j)
// {
// if (0 != *(dst + i * 4 * rct.Height() + 4 * j) || 0 != *(dst + i * 4 * rct.Height() + 4 * j + 1) || 0 != *(dst + i * 4 * rct.Height() + 4 * j + 2))
// {
// *(dst + i * 4 * rct.Height() + 4 * j + 3) = 200;
// }
// }
//}
BLENDFUNCTION oBlend;
oBlend.BlendOp = 0; //theonlyBlendOpdefinedinWindows2000
oBlend.BlendFlags = 0; //nothingelseisspecial...
oBlend.SourceConstantAlpha = 255;//0~255//AC_SRC_ALPHA
oBlend.AlphaFormat = 1; //...
POINT ptSrc = { 0, 0 };
POINT ptWinPos = { rct.left, rct.top };
SIZE sizeWindow = { rct.Width(), rct.Height() };
::UpdateLayeredWindow( m_hWnd, dc.GetSafeHdc(), &ptWinPos, &sizeWindow, hdcMemory1, &ptSrc, RGB( 0,0,0 ), &oBlend, ULW_ALPHA );
DeleteObject( hBitMap1 );
DeleteDC( hdcMemory1 );
}
谢谢您的查看!希望大家能帮一下,目前很困惑。