问题描述
我工作的一个透明的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 ):
-
让树做它的默认画在内存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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!