Redraw in parent window in child window's onPaint in mfc - c++

I am trying to implement something like this in mfc:
A parent window that contains a few child windows. I want some horizontal and vertical grid lines to appear around a child window when ever the window is being dragged anywhere inside the parent. For that, I am tracking movement in my OnPaint() handler for the child and accessing the parent and drawing these grid lines around the child. But its not behaving the way I want it to.
My guess is that the child's OnPaint() only updates the child's drawing region, so even if I do access the parent's DC, I cant draw anything on it unless it's being redrawn?
Can anybody suggest a neater method of achieving above functionality? What am I doing wrong? I need everything to happen in the child's OnPaint()

One way is to just pass data to the parent window and call its Invalidate function. Then it would paint the grid lines in its own OnPaint.
Or you could paint directly on the parent window from the child, but use the parent's GetDC function instead of using the child's DC.

One way to solve this problem is to draw a semi-transparent grid window using UpdateLayeredWindow on top of the parent client area while you arrange the child window on top of it. The grid window can then be destroy after the arrangement is done. In this way, there will be minimum changes required to the existing display code.

Related

How to create a child window is transparent and the parent window is not transparent?

I want to create a window with two child windows. Only the background of the top child window is transparent. I can directly see the background of the parent window and not the content of other child windows.Like the picture, A is parent, B is child 1, C is child 2.The background of child 2 is the same as parent.enter image description here
A-a-m,
You paint background on child window by yourself.
There is method OnPaint (in MFC) or message WM_PAINT.
And you should draw transparent background (it means to draw nothing).
Does it work?
If you use non-standart framework to create windows, you should specify background is painted programmatically.
A few options to experiment with:
If in your open source UI framework you can remove the WM_PAINT
handler entry in the Def­Window­Proc then you could do that.
Handle the WM_PAINT message yourself and do nothing in the handler except clear any flag that indicates that the client area
needs to be re-drawn. You'll need to find something equivalent to
ValidateRect.
Both of these methods MIGHT cause non client areas like the window frame to artifact within the client area as you move window C around but I can't be sure.

How to remove the output of Bitblt? (MFC)

I have outputted an image (bitmap) which is created by Bitblt.
Now I want to get rid of it. How can I do? (Do not use the patch, like FillSolidRect, etc.)
There is no way to "undo" or "erase" a BitBlt or any other drawing output (except in very special cases where you do XOR-based drawing, which you can undo by doing another XOR drawing operation on top of the original).
The only thing you can do is to draw on something else on top of it, which is what you are calling a "patch". Typically, you would draw a solid rectangle of the window's background color. This is precisely what the OnEraseBkgrnd message handler does by default, which runs just before OnPaint. Specifically, it uses your window class's background brush, which is typically a brush that draws using the COLOR_3DFACE (for a dialog) or COLOR_WINDOW (for a window) system color.
Of course, you could always just not do the BitBlt in the first place. All painting code should always go inside of the OnPaint message handler function, so there is no way that you could end up with "stale" graphics. Whenever the window needs repainting, it is going to call this function, and your code inside of that function will repaint the window. If you don't want it to be painted with a bitmap, don't call BitBlt.
If you've done a BitBlt on top of your window using a temporary CDC object (which you generally should not be doing), you can force this to be erased by triggering a repaint of the window. The easiest way is to use the window's InvalidateRect() member function; passing NULL as the pointer to the rectangle to be invalidated will invalidate the window's entire client area, or you can just invalidate the area that you blitted.

Custom button shape

I want to implement a simple volume up/down button using a custom bitmap, and all it's going to have is a simple hover effect, and mouse down effect.
My first idea was to process WM_MOUSEMOVE for the hover, and process WM_LBUTTONUP and WM_LBUTTONDOWN for the mouse down effect.
First, is this the easiest way to do this? I could superclass a button and just paint the bitmap and forget about the text...
Then I have the problem with the background, which should be transparent, I know I can use a mask by passing SRCAND to BitBlt, but this requires me to have 2 images for each button. Is there any way to do this with just one image? Like if I put a green background on it in my image editor, could I mask that out with a green screen like effect?
You need to create a regular button, and subclass it with SetWindowSubclass. The button must have the owner-draw style on it, which means in the parent WndProc, you are handling WM_DRAWITEM. As you correctly say, you will be BitBlt'ing or StretchBlt'ing the background of the image on.
For hover events you must do the following:
Have some sort of shared boolean between the parent and subclassed WndProc, eg. IsMousedOver
In the subclassed WndProc, process WM_MOUSEMOVE. When this message is hit, you should set IsMousedOver, then invalidate the control with InvalidateRect (this will trigger WM_DRAWITEM in the parent)
In the parent WndProc, if you receive WM_MOUSEMOVE, you should clear IsMousedOver
In WM_DRAWITEM in the parent WndProc, you should check IsMousedOver and BitBlt based on that state
If you want to process MouseUp/MouseDown, you can change the boolean to an int instead and have a tri-state. However, most implementations have MouseDown being the same as the regular button, and MouseUp is then simply the regular moused over background.
As for your query about 2 images, it may well be possible to do it with one but I haven't tried that before.

Child Window painting problem on Vista only

I have a dialog-based MFC C++ app. My dialog displays a number of "pages" (similar to a tab page or property dialog box).
I display each "page" by displaying a Child window over the top of the parent's client area. This works fine on Vista until I then open another window on top of the child.
Vista then seems to draw a thick white rectangular frame within my parent dialog box which paints over the top of my "page" child window(s). If I move another window over the top of this white rectangle, it will repaint the obscured area just fine.
Can somebody please tell me what is going on? Is Vista trying to clear my non-client (frame) area using incorrect coordinates perhaps?
My parent dialog is a skinned class derived from CDialog which handles the painting of my own window titlebar and frames. I've found that if I don't call CDialog::OnNcActivate() within my own OnNcActivate() method, the white rectangle doesn't appear. Of course if I do this then I can't use my child windows.. but OnNcActivate would appear to be related to the problem.
I've figured out the problem.. I shouldn't be calling CDialog::OnNcActivate() - I should have just been returning TRUE instead. All working fine now.

Can I force a parent window to redraw without causing its children to redraw?

Is it possible to invalidate a window without invalidating its children? (display invalidation to cause a repaint of the parent window, but not redraw its children)
This assumes that the parent window already has the "clipchildren" style, so that its painting wouldn't inherently invalidate the children.
InvalidateRect() already does this. Another way is RedrawWindow() with the RDW_NOCHILDREN option.
Parent windows are always going to redraw any child windows that intersect with the window's update region.
So, really, to get the behaviour you want, when invalidating the parent window - exclude the child rects from the region you pass to InvalidateRegion.