Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: How to get an accurate image of a control


This question is answered. Helpful answers available: 2. Correct answers available: 1.


Permlink Replies: 3 - Last Post: Oct 9, 2015 1:26 AM Last Post By: Martin Nijhoff
Martin Nijhoff

Posts: 75
Registered: 8/26/10
How to get an accurate image of a control  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 12, 2015 4:37 AM
Hi,

I'm working on a transparent panel component with alpha transparency. For this purpose, I need to get an image of the controls that are underneath the panel in a memory bitmap. This bitmap is later alpha blended with a bitmap of the panel's image.

So far, I found two ways to let the controls underneath the panel paint themself into the memory bitmap:


Method 1

Ctrl->PaintTo(DC, Ctrl->Left, Ctrl->Top);


Windows theme:
- Scroll bars are not painted (TMemo, TScrollBox, TStringGrid).
- Border of TScrollBox is painted incorrectly (border in clBtnShadow/clBtnHighlight instead of 3D bevels).
- Border of TEdit and TMemo is painted incorrectly (flat border instead of Windows theme).
- Border of TEdit and TMemo is painted incorrectly when focused (should be highlighted, but painted normal).

Visual styles:
- Scroll bars of nested controls are not painted (e.g. TMemo inside TScrollBox).
- Space between horizontal and vertical scroll bars is not painted.


Method 2

Ctrl->Perform(WM_PRINT, WPARAM(DC), LPARAM(PRF_CHECKVISIBLE | PRF_ERASEBKGND | PRF_NONCLIENT | PRF_CLIENT | PRF_CHILDREN));


Both:
- Nested controls are not clipped (e.g. controls inside TScrollBox).

Windows theme:
- Border of TEdit, TMemo and TStringGrid is painted incorrectly (3D bevels instead of Windows theme).

Visual styles:
- Most controls are painted incorrectly (TButton, TCheckBox, TComboBox, TGroupBox, TPageControl, TRadioButton: Windows theme instead of visual style).
- Border of TEdit, TMemo and TScrollBox is painted incorrectly (3D bevels instead of visual style).
- Scroll bars of nested controls are painted incorrectly (Windows theme instead of visual style).
- Space between horizontal and vertical scroll bars is painted incorrectly (color of Windows theme instead of visual style).


I tested both methods with standard controls like TButton, TEdit, etc. and default properties. Controls that support it, were tested with ParentBackground = false.

Neither method produces an accurate image of all controls for both the Windows theme and visual styles.

Ideally, you would send the controls a WM_ERASEBKGND, WM_NCPAINT and WM_PAINT message with the device context of the memory bitmap to have them paint themselves. However, the WM_NCPAINT message doesn't include a device context. I guess this is why the controls are not always painted correctly.

Is there a way to get an accurate image of any control, without painting it completely myself?

A screen grab is not an option, because the controls have to be painted in-memory (to avoid screen flicker).

--
Martin

Martin Nijhoff

Posts: 75
Registered: 8/26/10
Re: How to get an accurate image of a control  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 20, 2015 2:06 AM   in response to: Martin Nijhoff in response to: Martin Nijhoff
In the end, getting an accurate image of a control boils down to getting the non-client area painted into a memory bitmap.

Since WM_NCPAINT doesn't provide a device context, windowed controls that handle WM_NCPAINT call GetWindowDC(Handle) to obtain a device context for the window.

I know how to replace a control's window handle (returned by the Handle property) before calling Control->Perform(WM_NCPAINT, 1, 0) and restoring it afterwards.
This way, I can use a 'stand-in' window with its own device context (using the CS_OWNDC class style).
By copying the window and extended window styles, the non-client area of the 'stand-in' window is painted identical to the original window's non-client area.

Unfortunately, the non-client area only gets painted when the 'stand-in' window is visible (regardless of the CS_OWNDC class style).
Moving the 'stand in' window off-screen or hiding it, results in the non-client area not being painted.

So, unless I'm missing something, the 'stand-in window' method is a dead end.

Is there any way to replace the device context of a window (i.e. assign the device context of a memory bitmap to a window)?

Or is there any way to replace the device context handle returned by GetWindowDC() or even redirect the call to GetWindowDC() itself?

--
Martin
Sune Andersen

Posts: 13
Registered: 4/2/03
Re: How to get an accurate image of a control  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 20, 2015 10:00 AM   in response to: Martin Nijhoff in response to: Martin Nijhoff
Martin Nijhoff wrote:
Unfortunately, the non-client area only gets painted when the 'stand-in' window is visible (regardless of the CS_OWNDC class style).
Moving the 'stand in' window off-screen or hiding it, results in the non-client area not being painted.

It must check somehow if it's visible then, maybe you can intercept that and trick it?

Or maybe there's a way to use transparency by hiding the stand-in window behind a transparent window that isn't actually transparent, or maybe has 1 transparent pixel?
Martin Nijhoff

Posts: 75
Registered: 8/26/10
Re: How to get an accurate image of a control  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 9, 2015 1:26 AM   in response to: Martin Nijhoff in response to: Martin Nijhoff
Method 3

PrintWindow(Ctrl->Handle, DC, 0);


On Windows 7 and earlier, only the visible parts of the control (not covered by other controls) are rendered.
On Windows 8, the entire control is rendered, even if completely covered by other controls.

Unlike WM_PRINT, PrintWindow() renders the non-client area in the appropriate visual style.

--
Martin
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02