C++ – Strategy for creating a layered window with child windows (controls)

alphaclayeredwinapi

I want to create an irregularily shaped/skinned window (just with rounded, alpha blended corners for now). Upon creating the top-level window i am processing the WM_CREATE message and do the following:

  1. Create a compatible memory DC
  2. Create a DIB section compatible with the window DC
  3. Select DIB into memory DC
  4. Do the drawing of my backdrop
  5. Apply alpha channel and premultiply RGB values
  6. Call UpdateLayeredWindow()

Later on I am planning on rounding of the edges by setting the alpha channel and premultiplying the bits in question to make that happen.

Now, if I create for instance a button in my window, it will not render itself. I know why, and I am trying to come up with an elegant solution to making my custom controls (child windows) here.

My initial approach was to ditch using child windows in the first place and just let the top level window do all the drawing and also input handling, hit testing, and so on. I found this to be way to tedious and instead I want to let Windows handle all this for me.

Now, I know if I create a child window, it of course behaves normally (e.g. reacting to user input), and I want to leverage this. I am planning on creating the child windows (custom controls) normally using CreateWindowEx() so they get a window handle, and recieve window messages without me having to worry about passing them manually.

Somehow I need to get these windows painted, and as I see it, the only possible way to do this is from the routine that paints the whole top level window. I need to invent some kind of logic to get the top level window's paint routine to paint my child windows whenever necessary. As far as I understand the UpdateLayeredWindow() function need to redraw the whole window.

Is it sensible to for instance have the child controls render an image of themselves that are sent to the top level window's paint routine? Like for instance the child window sending a user WM to the top level window passing pointer to its rendered bitmap as a WPARAM and pointer to a structure defining its position and size as a LPARAM.

Any better ideas? Does this make any sense at all?

Thanks,
Eirik

Best Answer

I think I'm going to go for this solution:

Top level window

The top level window maintains two bitmaps. One which is the displayed window and one without any of the child controls rendered. The latter one will only need redrawing when the window changes size. The window will have a message handler that renders a child control on the displayed bitmap. The message handler will expect a pointer to either a DIB containing the child control, or to the actual bits (not sure which is best at the moment), as the WPARAM, and a pointer to a structure containing the rectangle that the child shall be drawn into as the LPARAM. A call to BitBlt() will be made to clear out the underlying surface (this is where the other bitmap comes in) prior to an AlphaBlend() call for rendering the child control bitmap onto the displayed bitmap surface.

The parent window will call the EnumChildWindows whenever it is resized or for some reason need to redraw its children. There could of course be some kind of invalidation regime enforced here to reduce unnecessary rendering of the child controls. Not sure if the speed increase is worth the effort, though.

Child windows

Upon creation of the child control instance, an internal bitmap compatible with that of the top-level window is created. The child renders itself into this internal bitmap and whenever it needs redrawing it notifies its parent window via the SendMessage() function, passing a pointer to its bitmap as the WPARAM, and a RECT as the LPARAM defining its position and dimensions. If the parent needs redrawing, it issues a message down to all its child windows requesting their bitmap. Childs will then respond with the same message that they normally would send when they decide they need redrawing themselves.

Eirik

Related Topic