2 greenleaf 01 greenleaf_01 于 2013.08.06 17:55 提问

在MFC透明窗口(layer window)中,如何设定光标?
先概述一下,现在做一个项目,需要用一个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 );

}
谢谢您的查看!希望大家能帮一下,目前很困惑。

Csdn user default icon
上传中...
上传图片
插入图片
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!