I need a way to for a custom control (descended from TCustomControl) to tell if it is currently visible. I'm not talking about the .Visible property; I mean whether or not it's actually being displayed on-screen at the moment. Does anyone know how to do this?
How can I tell if a Delphi control is currently visible?
Asked Answered
Do you mean whether or not it is covered by another window? –
Calcite
I mean whether or not it's getting drawn to the screen. Being covered could be one reason. Another could be if it's been placed on a form that's been created but not shown yet. –
Lavella
A few years back I had the same kind of problem for a Form: I was looking for a way to determine if a Form is actually visible (even only partially) to the user.
In particular when it was supposed to be visible and Showing was True but the window was actually entirely behind another one.
Here's the code, it could be adapted for a WinControl...
{----------------------------------------------------------}
function IsMyFormCovered(const MyForm: TForm): Boolean;
var
MyRect: TRect;
MyRgn, TempRgn: HRGN;
RType: Integer;
hw: HWND;
begin
MyRect := MyForm.BoundsRect; // screen coordinates
MyRgn := CreateRectRgnIndirect(MyRect); // MyForm not overlapped region
hw := GetTopWindow(0); // currently examined topwindow
RType := SIMPLEREGION; // MyRgn type
// From topmost window downto MyForm, build the not overlapped portion of MyForm
while (hw<>0) and (hw <> MyForm.handle) and (RType <> NULLREGION) do
begin
// nothing to do if hidden window
if IsWindowVisible(hw) then
begin
GetWindowRect(hw, MyRect);
TempRgn := CreateRectRgnIndirect(MyRect);// currently examined window region
RType := CombineRgn(MyRgn, MyRgn, TempRgn, RGN_DIFF); // diff intersect
DeleteObject( TempRgn );
end; {if}
if RType <> NULLREGION then // there's a remaining portion
hw := GetNextWindow(hw, GW_HWNDNEXT);
end; {while}
DeleteObject(MyRgn);
Result := RType = NULLREGION;
end;
function IsMyFormVisible(const MyForm : TForm): Boolean;
begin
Result:= MyForm.visible and
isWindowVisible(MyForm.Handle) and
not IsMyFormCovered(MyForm);
end;
Thanks! That's precisely what I was looking for. –
Lavella
You are a hero. –
Yare
This code has a problem. If the form is moved beyond the boundaries of the screen, the result is always False. Even if the form is partially in the screen (and covered). –
Yare
Could you attach code to the OnPaint event? This is called very often and I think is only called when the control is actually going to be painted (eg is visible in the way you mean).
I'd go with this as a best indicator. You can never be sure because in Vista all apps draw to an off-screen bitmap which is then composed in the graphics card with the overlays etc. –
Saida
But presumably its still only drawn off screen if it is going to be shown onscreen at the moment? –
Skimp
I don't think it's safe to assume that WM_PAINT will only come when those pixels are about to hit the screen. With Desktop Composition (msdn.microsoft.com/en-us/library/aa969540%28VS.85%29.aspx), Windows keeps a cache of drawn windows for effects like Windows Flip (microsoft.com/windows/windows-vista/features/flip-3d.aspx) that may require all windows at once. Because of this, I'd expect that there might be some background cache-refreshes. –
Lumbricoid
Francesca's accepted answer works for most cases. However, it doesn't work if the form is moved beyond the boundaries of the screen.
Here is the better answer:
function IsMyFormCovered(const MyForm: TForm): Boolean;
var
RectForm, RectForeground: TRect;
hWndForeground: HWND;
begin
GetWindowRect(MyForm.Handle, RectForm);
hWndForeground := GetForegroundWindow;
if (hWndForeground <> MyForm.Handle) and (hWndForeground <> 0) then
begin
GetWindowRect(hWndForeground, RectForeground);
if (RectForm.Left < RectForeground.Right) and
(RectForm.Right > RectForeground.Left) and
(RectForm.Top < RectForeground.Bottom) and
(RectForm.Bottom > RectForeground.Top) then
Result := True
else
Result := False;
end else
Result := False;
end;
© 2022 - 2024 — McMap. All rights reserved.