Mason Wheeler
Mason Wheeler

Reputation: 84550

How can I tell if a Delphi control is currently visible?

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?

Upvotes: 11

Views: 8662

Answers (3)

Xel Naga
Xel Naga

Reputation: 956

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;

Upvotes: 0

Francesca
Francesca

Reputation: 21640

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;

Upvotes: 18

Toby Allen
Toby Allen

Reputation: 11213

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).

Upvotes: 2

Related Questions