Setting transparent background Win32 - windows

What I'm trying to do is very simple but there doesn’t seem to be a lot of information on it. Basically I have a normal non-transparent parent window and I want to place a child window (that has its own non-transparent controls) inside that parent window. So the only thing I have to do is to set the background brush of the child window transparent, but it still draws a white background. Tried using WS_EX_LAYERED style and SetLayeredWindowAttributes but it makes the child window invisible.

There are two basic ways to achieve "transparent" child controls on Windows:
Handle WM_CTLCOLORxxx messages in the parent window.
This is a convenient way to make existing controls support transparency. Each control will send a WM_CTLCOLORxxx message appropriate to the type of the control. If you create a brush that represents the background skin of the dialog, and return that from each message, the net effect will be as if each control was painted with a transparent outer area.
This fails however if you want alpha effects, or for controls to physically overlap each other.
Use WS_EX_COMPOSITED on the parent window.
Without this style, the window managers paint order of child windows is undefined, in practice, its top to bottom. When trying to alpha blend overlapping controls the result will be... unpleasant. WS_EX_COMPOSITED will ensure the child windows are painted bottom to top. Make sure that you DON'T use either the WS_CLIPCHILDREN or WS_CLIPSIBLINGS styles as that will prevent the overlapping areas from being painted at all.
You still need to do something clever via WM_CTLCOLORxxx messages as the standard controls are still going to try and fill their entire rect with dialog-background-grey.

Related

The correct method for drawing a bitmap image into a window

I have a function which takes a rectangular region of a bitmap image, rescales it to different dimensions, and draws it at some offset inside of a window within my dialog-box application:
void DrawImage(HANDLE hImageBitmap,
CDC* pDstDC,const CRect& dstRect,
CDC* pSrcDC,const CRect& srcRect)
{
pSrcDC->SelectObject(hImageBitmap);
pDstDC->SetStretchBltMode(HALFTONE);
pDstDC->StretchBlt
(
dstRect.left,dstRect.top,dstRect.Width(),dstRect.Height(),pSrcDC,
srcRect.left,srcRect.top,srcRect.Width(),srcRect.Height(),SRCCOPY
);
}
I create and maintain the window using a CWnd m_cImageWindow member variable.
I perform the drawing from the dialog-box's OnPaint handler as follows:
CDC* pDC = m_cImageWindow.GetDC();
CDC cDC;
cDC.CreateCompatibleDC(pDC);
CRect srcRect = ...;
CRect dstRect = ...;
DrawImage(m_hImageBitmap,pDC,dstRect,&cDC,srcRect);
cDC.DeleteDC();
m_cImageWindow.ReleaseDC(pDC);
I have two problems:
I see flickering whenever I change the drawing parameters. The standard way to solve this, from what I have read here and there, is by using a temporary DC for double-buffering. But as far as I understand, this is exactly what I am already doing.
If some of the destination region falls outside the window, it is painted over other controls within the dialog box. I am able to partially solve this by calling MoveWindow or SetWindowPos for each one of these controls. But I can still see the image flickering behind them. I have tried calling SetWindowPos in various different ways, hoping in vain that it would dictate a strict Z-order of the controls.
Thank you.
The painting of the image into the child window should be done in the WM_PAINT handler for that child window, not for the dialog. Your child window may need remember information provided by the parent dialog so that it can paint independently. By painting the window from the dialog's WM_PAINT handler, you're possibly painting more often than necessary (and possibly aren't causing a validation to occur in the image window).
The dialog should probably have the WS_CLIPCHILDREN window style and your image window should probably have WS_CLIPSIBLINGS. This will prevent the dialog controls from drawing over each other, and it can reduce flicker by allowing for more minimal updates.
If the image will always completely cover the entire image window, then you want to make sure there's no background erasing happening for the image window, as that can cause a flash of the background color which looks like painting. There are several ways to do this, but the easiest is probably to provide a WM_ERASEBKGND handler that just returns TRUE.
I found OnEraseBkgnd to be the right place to minimize flickering of drawn bitmaps.

Weird black pixels in the corners of CProgressCtrl controls

I have an MFC dialog (actual a dialog bar with in a dialog) that contains a progress bar with these strange black pixels in the corner. I have tried the following to remove them:
Change most of the border type styles and the transparent style of the control.
Override the OnEraseBkgnd in a class derived a CProgressCtrl.
Setting the background color of the control by PBM_SETBKCOLOR.
I have yet to find a way to remove these black pixel.
Here is an example of what it looks like:
It seems I have found the issue. When the progress bar performs its painting it was sending an WM_ERASEBKGND message to the dialog to get the background with which it would paint. Some how the DC brush origin was being messed up. Using the following code at the start of the function seems to have fixed the issue with no ill effects.
CRect rcClip;
pDC->GetClipBox(rcClip);
pDC->SetBrushOrg(-rcClip.left, -rcClip.top);
I've seen this occur when using ActiveX controls inside control containers that don't have a a window or proper Device Contexts (The VB6 frame control is one of these) but I'm not sure if the same problem applies to MFC windows and controls though.
Try making the control parent a normal static window.

Correct way to do transparent buttons in WINAPI

How do you make the button with overrided WM_PAINT transparent. So that you could see the form through it in all places except where something is drawn. At the same time avoiding the flicker.
I saw examples with SetBkMode(HDC, TRANSPARENT), using NULL_BRUSH, examples with CompatibleDC and BitBlts, but I'm not quite sure which is the correct way to go, and also, how it behaves when WM_CLIPCHILDREN is set on the parent window. Most of the experiments I did had some weird behavior as well. Can't find a good documentation on WM_ERASEBKGND/WM_CTLCOLOR/WM_PAINT/WS_EX_COMPOSITED/WS_CLIPCHILDREN/etc internal relations on MSDN at all.
Does anyone know where I could read about this topic with all the gotchas associated?
mmm, I've never found anything close to a authoritative document on this topic.
This just serves as my rather random memory dump trying to get controls to "play nice", when animated, on a window that was either skinned (normal non client area with a bitmap background), layered (to get a window with custom non client edges with drop shadow effects) or with extended Aero Glass (via the DwmExtendFrameIntoClient) effects.
SetBKMode(... TRANSPARENT) just ensures that text rendering does not fill in the background of the text with the current bk color.
WS_EX_COMPOSITED causes windows to paint the parent and all child windows to a back buffer when the parent is invalidated, and then paint the back buffer. This is flicker free, but NT 6.0 introduced the desktop window manager which does not honor WS_EX_COMPOSITED.
WS_CLIPCHILDREN prevents the child windows and the parent window painting the same area twice. But is contra indicated if you need to use group boxes, or tab controls.
WS_CLIPSIBLINGs could be useful if child windows overlap and cause flicker. again this style is useless if you need to use group boxes or tab controls.
The other problem with WS_CLIPCHILDREN is you can't paint a background in the parent widnows window proc and rely on a NULL brush to reveal the skin. You can return a brush from WM_CTLCOLORxxx messages to coerce some of the standard controls to paint their background with your skin bitmap.
WS_EX_LAYERED is another style that makes windows buffer the painting of your parent window. But the layered windows painter does not paint child windows at all, so you need to manually paint the child windows by sending WM_PRINTCLIENT messages. Not all controls support this message.
WPF gets around the lack of back buffered painting and alpha support by not creating actual child windows at all for its buttons.
Final take on the situation:
With a little work you can get a skin behind most standard controls easily. WS_CLIPCHILDREN and no background painting on the parent will mimimize flicker. Handle WM_CTLCOLORxxx to fill the background on the controls.
If you are using Group Boxes or TabControls to frame other controls you absolutely must get the Z-order correct if using WS_CLIPSIBLINGS.
By sending controls WM_PRINTCLIENT messages, and some subclassing, you can get standard controls to paint onto a DIBSection, which you can then manually (or use DWM worker functions) repair the alpha channel of, and then paint onto a layered window, or a window with extended aero glass. This is even flicker free, but controls that don't support WM_PRINTCLIENT, or frequently update themselves outside of WM_PAINT, will not display correctly.

How to paint transparent areas for child controls?

I have a CTabCtrl subclass which I'm trying overriding WM_PAINT to perform custom drawing. The only problem is, when I change the selected tab, I get artifacts left on the dialog where the old paint code hasn't been erased before the new code is painted on top. (The standard tab controls have the selected tab appear 2 pixels bigger than non-selected tabs, so when you change from selected to non-selected, you are left with the previous paint artifacts).
What is the best way of "repainting" this area? I've tried getting the parent control's DC and BitBlt'ing that onto the child's DC, but that doesn't work because the parent DC already contains an image of this control.
Do you override the WM_ERASEBACKGROUND message as well? You should probably do that and erase the area in the control.
You could use DrawThemeParentBackground to draw the background (XP and later) if you don't want to replace all the drawing logic.

How to create a transparent window with non-transparent child controls (or child windows)?

First, I'm working on Win32 with C++.
I have been trying to implement a transparent window with a child window which should remain 100% opaque. It seems that child controls cannot have opacity better(lower) than the parent and if I make my parent 100% transparent then my child control also inherits the transparency.
Code that I use -
SetLayeredWindowAttributes(GetParent(parentWindowHwnd), 0, 0, LWA_COLORKEY, LWA_ALPHA);
Any help?
Please also reply if I am not very clear with my question.
You can't do this unfortunately, child windows always have the same opacity as their parent. The Google Desktop Toolbar had a neat trick to give the illusion of an opaque textbox on a translucent background. They created two top level windows, one of the background and one for the textbox. Then they set the background window as the owner (not the parent) of the texbox. They then set the background as transparent. It's quite a bit of work to get right, but it's the only way to do it without rendering the whole thing yourself using UpdateLayeredWindow.
I'm certain you can do it the other way round, i.e. an opaque main window with a transparent child window, so the reverse may also be true. Have you tried unsetting the WS_EX_LAYERED flag for the child window and then redrawing it to make it completely opaque again?
// Remove WS_EX_LAYERED from the window styles
SetWindowLong(hChildWnd,
GWL_EXSTYLE,
GetWindowLong(hChildWnd, GWL_EXSTYLE) & ~WS_EX_LAYERED);
RedrawWindow(hChildWnd,
NULL,
NULL,
RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);
The MSDN page on Layered Windows may also help.
You cannot make a child control less transparent than its parent. The usual approach here is to give your window an irregular shape: not a rectangle. This is much older that alpha transparency - Think about a clock application: you can make your window circular if you wanted, even on windows 95.
This could be done using the Windows API function SetWindowRgn:
A simple (vb) example
Google results

Resources