Why isn’t my transparent static control transparent?

Date:October 28, 2011 / year-entry #261
Tags:code
Orig Link:https://blogs.msdn.microsoft.com/oldnewthing/20111028-00/?p=9243
Comments:    27
Summary:A customer reported that their application uses transparent static controls positioned over a bitmap image control, but even though they set the Transparent property on the static control, the static control isn't transparent. The customer was kind enough to provide clear steps to illustrate the problem: Open Visual Studio 2005 or 2008. From the menu,...

A customer reported that their application uses transparent static controls positioned over a bitmap image control, but even though they set the Transparent property on the static control, the static control isn't transparent. The customer was kind enough to provide clear steps to illustrate the problem:

  • Open Visual Studio 2005 or 2008.
  • From the menu, select File, New File, Visual C++, Resource Template File (RCT).

  • Right-click on the RCT file, select Add Resource, and add a bitmap named IDB_BITMAP1.

  • Open the dialog box (IDD_DIALOG1) and add a "Picture Control", specifying IDC_BITMAP_1 as its ID.

  • Change the IDC_BITMAP_1 type to Bitmap and change the value of the Image property to IDB_BITMAP1.

  • Add a "Static Text" control IDC_TEST_STATIC and set its caption to "This is a test".

  • Reposition the static control so it overlaps the IDC_BITMAP_1 control.

  • On the IDC_TEST_STATIC control, set the Transparent property to True.

  • Type Ctrl+T to test the dialog and observe that the static control is not transparent.
Dialog
This is a test

The Transparent property in Visual Studio corresponds to the WS_EX_TRANSPARENT window style, and the documentation explains that

WS_EX_TRANSPARENT: The window should not be painted until siblings beneath the window (that were created by the same thread) have been painted. The window appears transparent because the bits of underlying sibling windows have already been painted.

The observed behavior, therefore, matches the documentation: The control underneath (the bitmap control) paints first, and then the static control paints on top of it. And a static text control paints by filling with the background brush and drawing the text on top of it. You can customize this behavior by responding to the WM_CTL­COLOR­STATIC message:

HBRUSH CTestDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
 HBRUSH hbr = __super::OnCtlColor(pDC, pWnd, nCtlColor);
 if (pWnd->GetExStyle() & WS_EX_TRANSPARENT) {
  pDC->SetBkMode(TRANSPARENT);
  hbr = GetStockBrush(HOLLOW_BRUSH);
  // even better would be to use a pattern brush, if the background is fixed
 }
 return hbr;
}

The customer appreciated the explanation but was puzzled as to why the Transparent is available if it doesn't work. "We understand that we can use the WS_EX_TRANSPARENT window style to create a transparent window and it will be painted after its underlying siblings, but the window style by itself doesn't make the static control transparent. But if we have to write the code above, why is the Transparent property available in the Properties box?" They included a screen shot from Visual Studio where the built-in help text for the Transparent property reads "Specifies that the control will have a transparent background."

The WS_EX_TRANSPARENT style doesn't mean "transparent"; it means "paint over siblings." The style is called "transparent" not because it makes the window transparent but because it makes transparency possible. It is one of the steps (but not the only one) for making child controls render transparently. Another important step is ensuring that the control does not erase its background in its WM_ERASE­BKGND, and that's the step that the On­Ctl­Color override performs.

Why is the Transparent property offered for static controls when it doesn't actually work? Shouldn't it be disabled for static controls?

The reason why it is offered is that it is a general window style that can be set on any control. Visual Studio doesn't know which controls can render transparently and which ones don't, or what extra steps are necessary to get the ones who can render transparently to actually do so. It just exposes the WS_EX_TRANSPARENT style and hopes that you know what you're doing.

In retrospect, it was a poor chose of name for the style. And the incorrect online help doesn't make things any better.

Bonus chatter: Note that the WS_EX_TRANSPARENT extended style is overloaded. In addition to affecting painting, it also affects hit-testing.


Comments (27)
  1. I think there's no problem at all, because the blog software ate your image.

  2. Someone says:

    @JamesJohnston:

    Huh? There's no image at all, just an amazingly cool "HTML-art image" of a dialog.

  3. James Schend says:

    The "image" is creative use of CSS. It shows up fine for me, Chrome 14.

  4. voo says:

    Didn't work the first time when I read the article on FF7, but Raymond seems to have fixed it stealthily ;-)

  5. Joshua says:

    So that's why I never could get WS_EX_TRANSPARENT to work. I kept on trying to use it on top level windows and it only works if the overlapping windows are owned by the same thread.

  6. John L says:

    Doesn't show properly in Google Reader (the label appears below the white square)

  7. A. Skrobov says:

    Oh my! That "x" in the corner seems to work as a submit button!

  8. OK, now that I squint, I see there is a white square against a very very very light gray (almost white) background – or is it a very light brown?  I don't know.  I'm not sure why he picked a white square instead of, say, a bright red one.

    The background all looked the same to me at first and so I assumed there should have been an image there – since the example he gave was a customer placing a label over the image.

    Some of us have to work with crappy monitors that don't have good contrast…  Or we have bad eyesight…

  9. JamesWebb says:

    Doesn't matter how many times you report docs and source code samples for being bad and/or incorrect.

    Like the sample not following the docs or vice verse.

    Microsoft doesn't seem to care, they do not even bother to respond nor do they correct the mistakes.

    It doesn't surprise me windows programs have so many bugs in them since they are programmed based on what they read in the docs. Docs buggy == programs buggy.

    On that note, on slightly different topic, yet similar:

    The Hilo (code.msdn.microsoft.com/Hilo) devs have not responded to my question so perhaps you Mr Raymond can answer this question:

    HiloC++Commonsourcewindowfactoryimpl.cpp:

    "wcex.hCursor = nullptr; // If the class cursor is not null, the system restores the class cursor each time the mouse is moved."

    Isn't this inefficient behavior ?

    If setting the cursor in registerclass is bad then where should you do it ?

    Or can you not prevent this behavior / issue ?

    When i created a basic window sample and setting hCursor to nullptr i get the donut cursor animation until i move the cursor out of the example window or moving the cursor to resize the example window which change the cursor to resize then changes it back to the normal expected arrow cursor.

    Yes, i have checked RegisterClass/Ex and WNDCLASS/EX documentation. They mentioned something about it before but the new w8 design docs, have removed that hint. So i'm yet again in the dark about how to do it right.

    Thank you for taking the time to read and answer.

  10. alegr1 says:

    @JamesWebb:

    // If the class cursor is not null, the system restores the class cursor each time the mouse is moved.

    Take time to go to Windows SDK documentation and read "About cursors (Windows)" topic.

    "To override the class cursor, process WM_SETCURSOR message".

    A window gets WM_SETCURSOR every time the cursor is moved. If you just pass it to DefWndProc, it will set the cursor to the registered class cursor. If you handle the message without passing it to DefWndProc, you can leave the cursor unchanged, or set it to your own custom one.

  11. DWalker says:

    @JamesWebb:  This is not Raymond's Suggestion Box.  The Suggestion Box for future topics is currently closed due to the large backlog.  You may get some answers here, or you may not.  :-)

  12. asfdasdf says:

    Even if I knew whom to contact at MS to ask such a question (I don't) I'd never think of doing it because I'd just use google (or bing if you like) and find n explanations to this issue.. just wondering if the support people are annoyed at such requests or glad that it's not a harder problem (eg a stack dump with no further context given)..

  13. CherryDT says:

    @JamesJohnston: The colors depend on your Windows system colors. The "white" is actually the "window" color while the "light grey" is actually the "3D face" color.

  14. Puckdropper says:

    @JamesJohnston:  I've noticed something odd about certain screens.  The color (especially yellow) disappears at certain angles.  If you adjust your viewing angle, you might notice a color suddenly appear.

  15. Rick C says:

    @Puckdropper, CRTs don't usually do that, although most of us don't use them any more, of course.

  16. 640k says:

    This is yet another proof of ms releasing a half baked technology which requires a lot of additional coding to get working. EVERYTHING ms release is like this. Most often it's easier to code all things from scratch yourself instead.

    Because when you add features like resizing of windows, and want non-corrupt drawing of graphics (in xp, vista & w7), things like gdi's "transparent" drawing apis is not that easy to make sense of any longer.

    And don't be ridiculous, ofcourse visual studio can complain about setting the transparent bit on static window class. It's not like the static class will change it's behavior in the next windows hotfix. If the static class changes that much, ms will release a new sp/version of vs for sure because then it's not windows any more.

  17. voo says:

    @640k Yes sadly there are no higher frameworks by MS that make using these things much simpler and easier. Oh wait, if programming with .NET (insert whatever you want here) you don't have to worry about WS_EX_TRANSPARENT and still get transparent windows?

    Lowlevel stuff is by definition more complex, easier to get wrong and you won't get every small detail on first glance. The problems are complex, backwards compatibility has to be maintained, etc.

    That's why there are many great highlevel frameworks that abstract all these details away from you.

  18. John says:

    In hindsight, WS_EX_TRANSPARENT really was a terrible name.  As soon as we get that time machine running…

  19. JamesWebb says:

    @alegr1

    Thank you for helping.

    @DWalker

    I knew that even if i'd not known that it wouldn't have help my questions.

    I've pretty much lost hope for msdn forums and mail-lists so Raymond was a shot in the dark for help. Raymond continues to provide very useful and informative knowledge of how and why windows works the way it does and how to communicate with it correctly.

    We really do need more Raymond like blogs.

    [I try to discourage these "Raymond, please help me, you're my only hope!" requests by reminding people that even if I decide to answer their question, it'll be two years before they get to see the answer. -Raymond]
  20. Danny says:

    Tell your customer to switch from using Visual Studio to Delphi, that's the RAD IDE that works. Delphi stopped having any visual crappy issues since 90's, while VS still got'em high.

  21. Joshua says:

    @JamesWebb: When all else fails, read the Wine sources. They're the result of porting a library definition to a large sample of running programs so they're probably right.

  22. Please have the MSDN documentation updated so developers don't have to search for this (excellent) explanation somewhere else and everyone can understand the behaviour immediately.

  23. TC says:

    @JamesWebb: There's an art in asking questions properly. By "properly", I mean, in a manner designed to maximize your chances of actually getting an answer.

    Your Hilo forum question started: "Can the devs explain in detail why windows behaves like this?" If I were a dev, reading that forum, here's what I would have thought: "NO". That page is clearly a simple Q&A page. It's not the place for long and detailed explanations. So I wouldn't have read any further!

    Here's what might have worked better: "I don't understand the cursor management in the example code. Can someone suggest some relevant reading on Windows cursor management?"

    HTH

  24. Martin Richter says:

    The way to use WM_CTLCOLOR as shown here will never work, if the static cntrol needs an update. It nly works if the background control and static control are just displayed once and are not changed.

    Using a hollow background brush causes WM_ERASEBKGND to erase and clear nothing. And even if WS_EX_TRANSPARENT is set, the background of the static control is not repainted if SetDlgItemText/SetWindowText is executed for the static control! So the result are artifacts of the previous contents…

    From my understanding a repaint of the static control with WS_EX_TRANSPARENT has to repaint underlying sibling control too, but this isn't the case!

    Just my 2 cents!

  25. SimonRev says:

    Unfortunately, the real issue is that you cannot really do proper transparency with child hwnds — the only way to get it right with child hwnds is to have them all talking to each other so that they can fill their background with whoever is behind them.  Even then, I am not sure if you can fully remove the flicker problem.  

    I assume this is the main reason why technologies like WPF simply don't use HWNDs for child objects — the only way to draw things right is for the parent window to draw everything.

  26. Teo says:

    Oh boy! Since I moved into WPF-land, I truly appreciate how awful Windows GDI/User APIs are. I know why they are where they are, and I know that WPF/XAML/GC have their own problems. But they are a *huge* improvement over the old-style code.

    That said, the information in this post was helpful, so keep these tricks pumping out, sooner or later I will need one of them (as I already have plenty of times).

  27. @CherryDT, Raymond:  I have no special/unusual system configuration.  It is a Windows 7 box with Aero Glass turned on, with all default settings.  I'm not the type to change all my system colors.  The blog is viewed under Google Chrome 15.

    I think my point is still valid.  Use explicit colors that you know will have an easily-seen contrast, rather than using the client computer's default colors which apparently don't have good contrast on some versions of Windows.

Comments are closed.


*DISCLAIMER: I DO NOT OWN THIS CONTENT. If you are the owner and would like it removed, please contact me. The content herein is an archived reproduction of entries from Raymond Chen's "Old New Thing" Blog (most recent link is here). It may have slight formatting modifications for consistency and to improve readability.

WHY DID I DUPLICATE THIS CONTENT HERE? Let me first say this site has never had anything to sell and has never shown ads of any kind. I have nothing monetarily to gain by duplicating content here. Because I had made my own local copy of this content throughout the years, for ease of using tools like grep, I decided to put it online after I discovered some of the original content previously and publicly available, had disappeared approximately early to mid 2019. At the same time, I present the content in an easily accessible theme-agnostic way.

The information provided by Raymond's blog is, for all practical purposes, more authoritative on Windows Development than Microsoft's own MSDN documentation and should be considered supplemental reading to that documentation. The wealth of missing details provided by this blog that Microsoft could not or did not document about Windows over the years is vital enough, many would agree an online "backup" of these details is a necessary endeavor. Specifics include:

<-- Back to Old New Thing Archive Index