本文介绍了不正确的结果与TransparentBlt的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我工作的一个透明的TreeView控件。为了实现透明度,我已经子类的树,我重写 WM_PAINT (在我的 WM_ERASEBKGND 处理我只是返回 TRUE 滚动鼠标滚轮和其他相关信息都将妥善处理)。
为了使树的背景透明,我用下面的算法(基于<一个href=\"http://www.$c$cguru.com/cpp/controls/treeview/misc-advanced/article.php/c679/Using-a-bitmap-as-a-background-image.htm\"相对=nofollow>这个的 codeGuru 的文章):

I am working on a transparent treeview control. In order to achieve transparency I have subclassed the tree and am overriding WM_PAINT ( in my WM_ERASEBKGND handler I just return TRUE. Scrolling, mousewheel and other relevant messages are handled properly ).To make tree’s background transparent I am using the following algorithm ( based on this CodeGuru article ):


  1. 让树做它的默认画在内存DC(保存在 memDC )。

获取家长的另一种内存DC(保存在 finalDC )。

Get parent’s background in another memory DC ( saved in finalDC ).

地图树的和父母的坐标,以便我可以抓住父母的背景位图的正确部分。

Map tree’s and parent’s coordinates so I can grab correct portion of parent’s background bitmap.

使用结合这两个图像 TransparentBlt 和树木的背景色( TransparentBlt(finalDC,...,memDC,...) ;

Combine these two images using TransparentBlt and tree’s background color ( TransparentBlt( finalDC, ... , memDC, ... ); ).

在父窗口中我已实施 WM_PRINTCLIENT ,所以我可以其背景,一个简单的 :: SendMessage消息(复制到内存DC(步骤2)的getParent(HWND),WM_PRINTCLIENT,(WPARAM)finalDC,(LPARAM)(PRF_CLIENT)); 电话。结果我得到的是正确的对双方的的Windows XP 的Windows7 的:


In parent window I have implemented WM_PRINTCLIENT, so I can copy its background into memory DC ( step 2 ) with a simple ::SendMessage( GetParent(hwnd), WM_PRINTCLIENT, (WPARAM)finalDC, (LPARAM)(PRF_CLIENT) ); call. The result I get is correct both on Windows XP and Windows7 :

我获得与树的默认位图(步骤1):: DefSubclassProc(HWND,WM_PAINT,(WPARAM)memDC,0); 电话。在这里,结果正确上都的的Windows XP 的Windows7 的:

I obtain tree’s default bitmap ( step 1 ) with ::DefSubclassProc( hwnd, WM_PAINT, (WPARAM)memDC, 0 ); call. Here too, the result is correct both on Windows XP and Windows7:

的Windows XP 的(我不知道为什么上传影像错过复选框,一切都看起来不错我的电脑上):

On Windows XP ( I do not know why uploaded image misses checkboxes, everything looks fine on my computer ) :

的Windows7 的(我不知道为什么上传影像错过复选框,一切都看起来不错我的电脑上):

On Windows7 ( I do not know why uploaded image misses checkboxes, everything looks fine on my computer ) :

然而, TransparentBlt()电话后,最后的画面是不正确绘制:

However, after TransparentBlt() call, final picture is not drawn properly:

的Windows XP 的复选框是问题 - >

On Windows XP checkboxes are the problem ->

的Windows7 的一些白色留在信件 - >

On Windows7 some white is left in letters ->

这些图片是从出口设备上下文位图到文件(我已经修改的来实现这一点)。

These pictures are result of exporting bitmaps from device contexts into file ( I have modified this code to achieve that ).

下面是code段 WM_PAINT

case WM_PAINT:
    {
        // usual stuff
        PAINTSTRUCT ps;

        RECT rcClient = {0};
        GetClientRect( hwnd, &rcClient );

        HDC hdc = BeginPaint( hwnd, &ps );

        // create helper memory DCs
        HDC memDC = CreateCompatibleDC(hdc), finalDC = CreateCompatibleDC(hdc);

        // create helper bitmaps
        HBITMAP memBmp,  // default tree's paint
            finalBmp,    // parent's background image
            bmpOld, bmpOldFinal;  // needed for cleanup

        memBmp = CreateCompatibleBitmap( hdc,
            rcClient.right - rcClient.left,
            rcClient.bottom - rcClient.top );

        bmpOld = (HBITMAP)SelectObject( memDC, memBmp );

        // map parent and child rectangles

        RECT rcParent;
        GetClientRect( GetParent(hwnd), &rcParent );

        // upper left corners of the treeview, parent window
        POINT ptTreeUL, ptParentUL;

        // map tree's coordinates
        ptTreeUL.x = rcClient.left;
        ptTreeUL.y = rcClient.top;

        ClientToScreen( hwnd, &ptTreeUL );

        // map parent's coordinates
        ptParentUL.x = rcParent.left;
        ptParentUL.y = rcParent.top;

        ScreenToClient( GetParent(hwnd), &ptParentUL );

        /********* get parent's background image *******/

        finalBmp = CreateCompatibleBitmap( hdc,
            rcParent.right - rcParent.left,
            rcParent.bottom - rcParent.top );

        bmpOldFinal = (HBITMAP)SelectObject( finalDC, finalBmp );

        ::SendMessage( GetParent(hwnd), WM_PRINTCLIENT,(WPARAM)finalDC,
            (LPARAM)(PRF_CLIENT) );

        /********* capture default tree image *********/

        ::DefSubclassProc( hwnd, WM_PAINT, (WPARAM)memDC, 0 );

        // get tree's background color

        COLORREF clrMask = TreeView_GetBkColor(hwnd);

        if( clrMask == -1 )  // this means tree uses default system color
            clrMask = ::GetSysColor(COLOR_WINDOW);

        /**** combine tree's default image with parent's background ****/
        /**** so we can erase default background with parent's background ****/

        TransparentBlt( finalDC,
            ptParentUL.x + ptTreeUL.x,
            ptParentUL.y + ptTreeUL.y,
            rcClient.right - rcClient.left,
            rcClient.bottom - rcClient.top,
            memDC,
            0, 0,
            rcClient.right - rcClient.left,
            rcClient.bottom - rcClient.top,
            clrMask );

        // draw the result into tree's DC
        BitBlt( hdc,
            0, 0,
            rcClient.right - rcClient.left,
            rcClient.bottom - rcClient.top,
            finalDC,
            ptParentUL.x + ptTreeUL.x,
            ptParentUL.y + ptTreeUL.y, SRCCOPY);

        // cleanup
        SelectObject( memDC, bmpOld );
        DeleteDC( memDC );
        DeleteObject( memBmp );
        SelectObject( finalDC, bmpOldFinal );
        DeleteDC( finalDC );
        DeleteObject( finalBmp );

        EndPaint( hwnd, &ps );
    }
    return 0L;

我如何正确地与父母的背景结合起来默认的树位图,没有视觉假象实现透明度的?

How can I properly combine default tree bitmap with parent’s background, achieving transparency without visual artifacts ?

我能够通过开沟解决问题的复选框 TransparentBlt()和做事自己。

I was able to fix checkbox issue by ditching TransparentBlt() and doing things myself.

ClearType字体的仍然是一个问题,文物依然存在。面具创作是问题。随着成员的 ARX 的说,背景相结合是负责的。如果我能创造适宜的口罩那么我的问题将得到解决。

ClearType font is still a problem, artifacts remained. Mask creation is the problem. As member arx said, background combining is responsible for that. If I could create proper mask then my problem would be solved.

下面是整个类过程:

LRESULT CALLBACK TreeProc( HWND hwnd, UINT message,
    WPARAM wParam, LPARAM lParam,
    UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
{
    switch (message)
    {
    // handle messages that paint tree without WM_PAINT
    case WM_TIMER:  // handles autoscrolling when item is partially visible
    case TVM_DELETEITEM:
    case TVM_INSERTITEM:
    case WM_MOUSEWHEEL:
    case WM_HSCROLL:
    case WM_VSCROLL:
        {
            ::SendMessage( hwnd, WM_SETREDRAW, (WPARAM)FALSE, 0 );

            LRESULT lres = ::DefSubclassProc( hwnd, message, wParam, lParam );

            ::SendMessage( hwnd, WM_SETREDRAW, (WPARAM)TRUE, 0 );

            ::RedrawWindow( hwnd, NULL, NULL,
                RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW );

            return lres;
        }
    case WM_PAINT:
        {
            // usual stuff

            PAINTSTRUCT ps;
            HDC hdc = BeginPaint( hwnd, &ps );

            // get client coordinates of parent and tree window

            RECT rcClient = {0}, rcParent = {0};

            GetClientRect( hwnd, &rcClient );
            GetClientRect( GetParent(hwnd), &rcParent );

            // create helper DCs and bitmaps

            HDC memDC = CreateCompatibleDC(hdc),    //default tree paint
                finalDC = CreateCompatibleDC(hdc),  // parent's WM_PRINTCLIENT
                maskDC = CreateCompatibleDC(hdc);   // DC that holds monochrome mask

            HBITMAP memBmp,  // default tree's paint
                finalBmp,    // parent's background image
                maskBmp,      // monochrome mask
                bmpOld, bmpOldFinal, bmpOldMask;  // needed for cleanup

            memBmp = CreateCompatibleBitmap( hdc, rcClient.right - rcClient.left,
                rcClient.bottom - rcClient.top );

            bmpOld = (HBITMAP)SelectObject( memDC, memBmp );

            /****** get parent's background image *******/

            finalBmp = CreateCompatibleBitmap( hdc, rcParent.right - rcParent.left,
                rcParent.bottom - rcParent.top );

            bmpOldFinal = (HBITMAP)SelectObject( finalDC, finalBmp );

            ::SendMessage( GetParent(hwnd), WM_PRINTCLIENT,(WPARAM)finalDC,
                (LPARAM)(PRF_CLIENT) );

            /****** capture default tree image *********/

            ::SendMessage( hwnd, WM_PRINTCLIENT,(WPARAM)memDC, (LPARAM)(PRF_CLIENT) );

            /********** create monochrome mask *******/

            // get tree's background color

            COLORREF clrMask = TreeView_GetBkColor(hwnd);

            if( clrMask == -1 )
                clrMask = ::GetSysColor(COLOR_WINDOW);

            maskBmp = CreateBitmap( rcClient.right - rcClient.left,
               rcClient.bottom - rcClient.top, 1, 1, NULL );

            bmpOldMask = (HBITMAP)SelectObject( maskDC, maskBmp );

            SetBkColor( memDC, clrMask ); // this color becomes white, all others black

            BitBlt( maskDC, 0, 0, rcClient.right - rcClient.left,
                rcClient.bottom - rcClient.top, memDC, 0, 0, SRCCOPY );

            /***** map tree's coordinates to parent window *****/

            POINT ptTreeUL;

            ptTreeUL.x = rcClient.left;
            ptTreeUL.y = rcClient.top;

            ClientToScreen( hwnd, &ptTreeUL );
            ScreenToClient( GetParent(hwnd), &ptTreeUL );

            /***** creating transparent background ********/

            // mask the original image

            SetBkColor( memDC, RGB( 0, 0, 0 ) );
            SetTextColor( memDC, RGB( 255, 255, 255 ) );

            BitBlt( memDC, 0, 0,
                rcClient.right - rcClient.left,
                rcClient.bottom - rcClient.top,
                maskDC, 0, 0, SRCAND );

            // create transparent treeview image

            SetBkColor( finalDC, RGB ( 255, 255, 255 ) );
            SetTextColor( finalDC, RGB ( 0, 0, 0 ) );

            BitBlt( finalDC, ptTreeUL.x, ptTreeUL.y,
                rcClient.right - rcClient.left,
                rcClient.bottom - rcClient.top,
                maskDC, 0, 0, SRCAND );

            BitBlt( finalDC, ptTreeUL.x, ptTreeUL.y,
                rcClient.right - rcClient.left,
                rcClient.bottom - rcClient.top,
                memDC, 0, 0, SRCPAINT );

            // display the result

            BitBlt( hdc, 0, 0,
                rcClient.right - rcClient.left,
                rcClient.bottom - rcClient.top,
                finalDC, ptTreeUL.x, ptTreeUL.y, SRCCOPY );

            /***************** cleanup ******************/

            SelectObject( memDC, bmpOld );
            DeleteDC( memDC );
            DeleteObject( memBmp );

            SelectObject( finalDC, bmpOldFinal );
            DeleteDC( finalDC );
            DeleteObject( finalBmp );

            SelectObject( maskDC, bmpOldMask );
            DeleteDC( maskDC );
            DeleteObject( maskBmp );

            EndPaint( hwnd, &ps );
        }
        return 0L;
    case WM_ERASEBKGND:
        return TRUE;
    case WM_NCDESTROY:
        ::RemoveWindowSubclass( hwnd, TreeProc, 0 );
        return ::DefSubclassProc( hwnd, message, wParam, lParam);
    }
    return ::DefSubclassProc( hwnd, message, wParam, lParam);
}

在父窗口吸取 WM_PAINT 图像响应的(记得用(HDC )的wParam 而不是 BeginPaint的,以及收益率(LRESULT)0; )。我画了一个梯度可以在图片上面可以看出。

In parent window draw the image from WM_PAINT in response to WM_PRINTCLIENT ( remember to use (HDC)wParam instead of BeginPaint, and to return (LRESULT)0; ). I drew a gradient as can be seen on the pictures above.

在父窗口中必须添加在你的 WM_NOTIFY 处理以下内容:

In parent window you must add the following in your WM_NOTIFY handler:

case WM_NOTIFY:
    {
        if( ((LPNMHDR)lParam)->code == TVN_SELCHANGING )
        {
            InvalidateRect( ((LPNMHDR)lParam)->hwndFrom, NULL, FALSE );
            break;
        }

        if( ((LPNMHDR)lParam)->code == TVN_ITEMEXPANDING )
        {
            InvalidateRect( ((LPNMHDR)lParam)->hwndFrom, NULL, FALSE );
            break;
        }
    }
    break;

只有字体仍是固定的。

Only font remains to be fixed.

推荐答案

在Windows 7中的文本平滑抗锯齿。 Windows不搽纯色背景黑色文本像素,它描绘黑色,背景色之间的过渡。

On Windows 7 the text is smoothed with anti-aliasing. Windows doesn't paint pixels of black text on a background of solid colour, it paints a blend between black and the background colour.

TransparentBlt 把单一的纯色透明。因此,它不会将文本作为透明的抗锯齿边缘,所以这些边缘在最后的位图可见。

TransparentBlt treats a single solid colour as transparent. Hence it doesn't treat the antialiased edges of the text as transparent, so these edges are visible in the final bitmap.

要解决这个问题,你可以选择具有抗混叠禁用的字体,但显然这会给你更多的波诡云谲的文字。

To fix this you could select a font with anti-aliasing disabled, but obviously this will give you more lumpy text.

这是XP的问题是,检查盒的角落的颜色与背景色相同。您可以通过更改背景颜色不冲突(例如品红色)可能是解决这个问题。

The problem on XP is that the corner of the check-boxes is the same colour as the background. You can probably fix this by changing the background to a colour that doesn't clash (e.g. magenta).

这篇关于不正确的结果与TransparentBlt的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-13 12:19