0

I could begin by asking the question outright or by citing my sources (this, this, this, and this) descriptively, but I'll walk you ll through what I'm trying to do instead.

Let's start with a main window. It has its own window class whose hbrBackground is set to COLOR_BTNFACE + 1. Now let's do

EnableThemeDialogTexture(hwnd, ETDT_ENABLE | ETDT_USETABTEXTURE)

so the tab control we're about to add will be drawn with visual styles. (Try Windows XP with the standard Luna theme for best results.) Now let's add a tab control and two tabs.

On the first tab, we create an instance (let's call it container) of a new window class. This window class is going to hold various controls. I could set hbrBackground to COLOR_BTNFACE + 1, but then it will draw over the tab background. So I want this new child window to be transparent. So what I do is

  1. set the class hbrBackground to GetStockObject(HOLLOW_BRUSH)
  2. set container's extended style to WS_EX_TRANSPARENT
  3. set the class WM_ERASEBKGND handler to do SetBkMode((HDC) wParam, TRANSPARENT); return 0; to set the device context and have Windows draw the transparent background.

So far so good, right? I'm not sure if I'm really doing all this correctly, and I'd like this to also be flicker-free, which doesn't seem to happen: when I resize the window (at least in wine) I get either flicker or garbage drawn (even in child controls, somehow!). Windows XP in a VM just shows flicker. I tried tweaking some settings but to no avail.

But wait, now I want to have another control, one that just draws some bitmap data. On the next tab, create another container, then have a third window class area as a child of that. area only draws in the upper-left 100x100 area and has scrollbars; the rest of the window area should be transparent.

Right now, what I have for area is:

  1. the window class hbrBackground set to NULL and styles CS_HREDRAW and CS_VREDRAW set
  2. the extended window style being 0
  3. the WM_ERASEBKGND simply doing return 1;
  4. the WM_PAINT filling the entire update rect with COLOR_BTNFACE + 1 before drawing, and rendering all of it

This is flicker-free, but obviously not transparent. NOW I'm really not sure what to do, because I want the area to be transparent in such a way that it shows the tab control background. Again, I tried tweaking settings to bring them closer to what I tried above with container, but I got either flicker or invalidation leftovers when I tried.

So how do I get both of these custom control types (the container and the drawing area) to be both flicker-free and transparent?

I presently must target Windows XP at a minimum, though if the solution would be easier with Vista+ only I'd be happy to keep that solution on the side in case I ever drop XP support (unfortunately Stack Overflow doesn't let me hand out silver medals...).

Thanks!

andlabs
  • 11,290
  • 1
  • 31
  • 52

1 Answers1

1

To paint your window in a manner that is "flicker free", you will need to paint your window to a bitmap, then copy the bitmap to the destination device context. On Windows XP, you will need to create a bitmap, adjust the origin of the drawing DC and then paint your window. On Vista and later you can use BeginBufferedPaint and its associated routines to do the buffering for you.

Once you have buffered painting working, you can then use WM_PRINTCLIENT to paint your window's parent window into the your drawing DC before you do any actual drawing. Unfortunately, not all windows will support WM_PRINTCLIENT.

You could consider using DrawThemeParentBackground, rather than WM_PRINTCLIENT directly.

Combining these two methods together will leave you with transparent flicker-free drawing.

William
  • 1,867
  • 11
  • 10
  • I'm trying to figure out how I use `WM_PRINTCLIENT` to print the parent window, since that message seems to print an entire client area. I suppose I need to adjust the origin of the DC to account for the difference between parent and child, correct? Thanks. – andlabs Aug 06 '14 at 14:08
  • 1
    @andlabs Yes, you can use MapWindowPoints or ClientToScreen and ScreentToClient to do the calculate the correct values for the origin. – William Aug 06 '14 at 17:18
  • Also, which function will change the DC origin? I tried looking but there doesn't seem to be a `SetDCOrg` or `SetDCOrgEx` to go along with `GetDCOrgEx`; this DC comes from `BeginPaint` but it can come from `BeginPaintBuffered` too. Thanks! – andlabs Aug 06 '14 at 21:59
  • Ah, found it; it's `SetWindowOrgEx` (after `ScreenToClient` to convert the result of `GetWindowRect` on `container` to the in-client coordinates of the tab). That settles the transparent bit; now to add the flicker-free bit and apply that to `area`. I'll check the answer once I get everything working. Thanks again! – andlabs Aug 07 '14 at 01:33
  • All right, I can't seem to get flicker-free working. Here's my code: http://pastie.org/9453628 I tried clipping children as someone suggesting but that also didn't work (and if I do it to rdc then I get weird black and white chunks as artifacts). What am I doing wrong here? Thanks. – andlabs Aug 07 '14 at 17:51
  • Remove the WS_EX_TRANSPARENT style from your child window. You should not need to clip children in your "containerClass" window. You *may* need to add WS_CLIPCHILDREN to the parent window, or at least ensure that it isn't erasing the background where the child control exists. Start with removing WS_EX_TRANSPARENT. You may also want to override the WM_ERASEBKGND and WM_PAINT messages for the parent window and do nothing (don't erase and call BeginPaint/EndPaint only) .. that will leave your window unpainted and you can see if the parent window is causing the flickering by painting below. – William Aug 07 '14 at 18:53
  • Removing WS_EX_TRANSPARENT did get rid of a lot (but not all) of the flickering (why?), but also exposes a bunch of very subtle drawing errors (you have to pay attention to notice, such as very pale lines under the tab control or white boxes near the top). I removed the clipchildren logic as well; will try the parent window (and tab control too, just to be safe + I already have it subclassed anyway) clipchildren and drawing disable tricks later and report back. – andlabs Aug 07 '14 at 19:11
  • Actually scratch that; not sure what happened there. Removing WS_EX-TRANSPARENT causes my background to go black (b/c no WM_PRINTCLIENT) and flickering to continue (with what appears to be shearing...). Using WS_CLIPCHILDREN caused my toplevel window client to go black and the tab control to flicker black with resizing... If I start clean (with WS_EX_TRANSPARENT and no other changes) and tell the toplevel not to paint, most of the flickering goes away. If I tell the tab control not to paint as well, more does (but still not all). – andlabs Aug 07 '14 at 21:38
  • Flickering is caused by the same pixels being painted more than once. You need to figure out which windows are painting the area. Use Spy++ to ensure the parent hierarchy of your window and that all of the parent's have WS_CLIPCHILDREN style. Maybe you could create a separate project with just your container and one top-level window as it's parent to see if you can eliminate the flicker there. – William Aug 08 '14 at 04:14
  • Spy++ shows the parent hierarchy is correct: toplevel -> container -> tab -> container 2 -> various common controls. Which of these do I need to have CLIPCHILDREN on? I know for a fact that right now (reverted to clean repo) none of them are. Spy++ does tell me the toplevel and tab control have CLIPSIBLINGS, if that helps... (I did not set those manually, so IDK how.) I can produce another test program later. – andlabs Aug 08 '14 at 04:45
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/58927/discussion-between-william-and-andlabs). – William Aug 08 '14 at 05:23
  • Update for future readers: I never figured out the cause of the flicker, but I removed every bit of custom draw and it still happens, so I assume there's an issue elsewhere... Thanks in the meantime! – andlabs Aug 14 '14 at 22:14
  • http://stackoverflow.com/questions/25319918/once-and-for-all-how-do-i-get-a-fully-transparent-checkbox-button-radio-butto/25551622#25551622 Thanks for the help with this... – andlabs Aug 28 '14 at 14:43