Direct2D: Opaque child windows over a transparent parent window

1.6k Views Asked by At

I'd like to create a Direct2D application that has a transparent background on which a few opaque complex controls are placed. The problem can be broken into several sub-problems:

Architecture: Should the controls be implemented as child windows? I think that this is the correct approach, rather that creating Direct2D polygons that implement a child-window functionality.

I tried to implement this by initializing the parent window:

SetWindowLong(m_hwnd, GWL_EXSTYLE, GetWindowLong(m_hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
SetLayeredWindowAttributes(m_hwnd, 0, (255 * 50) / 100, LWA_ALPHA);

And create the child window as WS_CHILD. This resulted in a child on which all D2D drowings including background are transparent. I could not find a way to make the child opaque. When I create the child window as WS_POPUP or WS_OVERLAPPED the opacity problem is solved but the child window is located on the desktop unrelated to the parent.

Layered Window? I chose to work with Layered Windows but since I target at VistaSP2 and higher there might be better solutions. I tried the solution offered here but I too failed to implement it.

1

There are 1 best solutions below

0
On

Do you mean to create a 32-bit-per-pixel window? (Sorry for being unable to comment, not enough rep over here)

In that case, you are FORCED to use UpdateLayeredWindow (and a CreateDIBSection call while you initialize), no matter what, every time you finished drawing the scene, after you finished drawing the scene, like:

// Draw to your D2D1 RenderTarget here
RECT rcWin = {0};
GetWindowRect(hWnd,&rcWin);
POINT ptw = {rcWin.left,rcWin.top};
SIZE pts = {rcWin.right-rcWin.left,rcWin.bottom-rcWin.top};
POINT ptsrc = {0};
HDC ScreenDC = GetDC(0);
UpdateLayeredWindow( hWnd, ScreenDC, &ptw, &pts, MemDC, &ptsrc, 0, &bf, ULW_ALPHA);
ReleaseDC(0,ScreenDC);

About the initialization:

RECT r = {0};
GetWindowRect(hWnd,&r);
HDC scrDC = GetDC(0);
MemDC = CreateCompatibleDC(scrDC);
ReleaseDC(0,scrDC);
if(!MemDC)
    { FailInit(); }
BITMAPINFO bmi = {0};
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biWidth = r.right-r.left;
bmi.bmiHeader.biHeight = r.bottom-r.top;
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
DIBSectionBitmap = CreateDIBSection(MemDC,&bmi,DIB_RGB_COLORS,0,0,0);
if(!DIBSectionBitmap)
    return 0;
OldBmp = (HBITMAP)SelectObject(MemDC,DIBSectionBitmap);
// Now create the HWND D2D1 RenderTarget.

About the freeing of the resources:

// Free the D2D1 RenderTarget here
if(MemDC && OldBmp)
    SelectObject(MemDC,OldBmp);
if(DIBSectionBitmap)
    DeleteObject(DIBSectionBitmap);
if(MemDC)
    DeleteDC(MemDC);
MemDC = 0;
OldBmp = 0;
DIBSectionBitmap = 0;

EDIT: MemDC, OldBmp and DIBSectionBitmap are Per-Window. MemDC is a HDC. OldBmp is a HBITMAP. DIBSectionBitmap is a HBITMAP. At this point you can draw your child windows as if they were part of your very own main window, with a per-pixel alpha precision, but you'll need to handle focusing and messaging on your own.