Place a border around windows/controls on mouseover

As the title suggest I am looking for a way to place a  border around any window/control on my computer when I move my mouse over it as long as I have the mouse button down and when I let go of the mouse button the border will disapper.

If it helps I am trying to make a SnagIT clone which for those of you that dont know is a screen capture utility and I have everything working fine except I would like to know what window/control I have the mouse over at the time in a visual manner so I know exactly what I am taking the screenshot of.

Hope that helps and thx for all replies in advance.
voodoo22Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

pcsentinelCommented:
Not sure if this will help, but in order to find out what control you are over then you need to descend through all parents on a form, I use this for a slightly differnet reason but it may be of use

procedure TfrmMain.AppMessage(var Msg: TMsg; var Handled: Boolean);
var
      lEn: boolean;
  lCon: tControl;
  lCon2: tControl;
  lp: tpoint;
  lc: tPoint;
  lGotLast: boolean;
begin
  if (Msg.Message = WM_LBUTTONDOWN) then
  begin
            lc:=Mouse.CursorPos;
            Handled:=true;
            lp:=ScreenToClient(lc);
            //get the control at this position
            lCon:=ControlAtPos(lp,true,true);
            //now need to descend through the controls until get to last control at mouse position
    if lCon is tWinControl then
    begin
                  lGotLast:=false;
                  while not lGotLast do
      begin
if lCon is tWincontrol then
          begin
            lp:=(lCon as TWinControl).ScreenToClient(lc);
            lCon2:=(lCon as TWinControl).ControlatPos(lp,true,true);
            if lCon2=nil then
              lGotLast:=true
            else
              lCon:=lCon2;
          end
          else
                lGotLast:=true;
end;
    end;
end;

this should leave you with lCon being the control under the mouse.


appmessage will override default handling if you put handled:=true; into the code.

As for drawing a border around a control its not straightforward as it depends on what the control is placed on, however you may be able to use the canvas of the form and use DrawRect using the info from the control returned from the above code


Hope this helps
0
pcsentinelCommented:
Forgot to say that I have assumed that you dont want to actually process anything when you are is this mode i.e. you dont want the left click to actually do anything, so you add handled:=true into the code otherwise you could just use screen.activecontrol
0
voodoo22Author Commented:
thx for the info but I know how to get the control under the mouse part im just having difficulty with drawing a border around it.
0
Cloud Class® Course: Ruby Fundamentals

This course will introduce you to Ruby, as well as teach you about classes, methods, variables, data structures, loops, enumerable methods, and finishing touches.

pcsentinelCommented:
Try this

declarations

  private
        FLast: TWincontrol;
    procedure AppMessage(var Msg: TMsg; var Handled: Boolean);


procedure TForm1.FormCreate(Sender: TObject);
begin
      Application.OnMessage:=AppMessage;

end;



procedure TForm1.AppMessage(var Msg: TMsg; var Handled: Boolean);
var
      lEn: boolean;
  lCon: tControl;
  lCon2: tControl;
  lHelp: integer;
  lp: tpoint;
  lp2: tpoint;
  lc: tPoint;
  lGotLast: boolean;
  lRect: TRect;
  lDC: HDC;
  lPen: HPen;
begin
  if (Msg.Message = WM_LBUTTONDOWN) then
  begin
            lc:=Mouse.CursorPos;
            Handled:=true;
            lp:=ScreenToClient(lc);
            //get the control at this position
            lCon:=ControlAtPos(lp,true,true);
            //now need to descend through the controls until get to last control at mouse position
    if lCon is tWinControl then
    begin
                  lGotLast:=false;
                  while not lGotLast do
      begin
                              if lCon is tWincontrol then
          begin
            lp:=(lCon as TWinControl).ScreenToClient(lc);
            lCon2:=(lCon as TWinControl).ControlatPos(lp,true,true);
            if lCon2=nil then
              lGotLast:=true
            else
              lCon:=lCon2;
          end
          else
                lGotLast:=true;
                  end;
    end;
            if lCon<>nil then
    begin
      lp:=(lCon as TWinControl).Clienttoscreen(Point(0,0));
      lp2:=(lCon as TWinControl).Parent.Clienttoscreen(Point(0,0));
      lRect.Left:=lp.x-lp2.x-4;
      lREct.Top:=lp.y-lp2.y-4;
      lRect.Right:=lRect.Left+(lCon as TWinControl).Width+4;
      lRect.Bottom:=lRect.Top+(lCon as TWinControl).Height+4;
      if assigned(FLast) then
            FLast.Repaint;
      lDC:=GetDC((lCon as TWinControl).Parent.Handle);
      lPen:=CreatePen(PS_SOLID,4,clRed);
      SelectObject(lDc,lpen);
      Rectangle(lDC,lREct.Left,lRect.Top,lrect.Right,lrect.Bottom);
      Handled:=true;
      FLast:=(lCon as TWinControl).Parent;
    end;
  end;
end;


this was a quickie so you might need to do some work on screen refresh;
0
pcsentinelCommented:
If you have got your own code for finding the control then you only need the section at the bottom i.e.

 private
       FLast: TWincontrol;

procedure DrawBorder(Con: TControl);
var
  lp: tpoint;
  lp2: tpoint;
  lc: tPoint;
  lGotLast: boolean;
  lRect: TRect;
  lDC: HDC;
  lPen: HPen;
begin
    if Con<>nil then
    begin
      lp:=(Con as TWinControl).Clienttoscreen(Point(0,0));
      lp2:=(Con as TWinControl).Parent.Clienttoscreen(Point(0,0));
      lRect.Left:=lp.x-lp2.x-4;
      lREct.Top:=lp.y-lp2.y-4;
      lRect.Right:=lRect.Left+(Con as TWinControl).Width+4;
      lRect.Bottom:=lRect.Top+(Con as TWinControl).Height+4;
      if assigned(FLast) then
           FLast.Repaint;
      lDC:=GetDC((Con as TWinControl).Parent.Handle);
      lPen:=CreatePen(PS_SOLID,4,clRed);
      SelectObject(lDc,lpen);
      Rectangle(lDC,lREct.Left,lRect.Top,lrect.Right,lrect.Bottom);
DeleteObject(lPen);
      FLast:=(Con as TWinControl).Parent;
    end;
  end;



Hope this helps
0
voodoo22Author Commented:
it doesn't appear to be donig nething. could you post the whole unit so I can see where Im making my mistakes thx.
0
pcsentinelCommented:
-------------------------------------Unit Code-----------------------------------------

unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Db, Grids, DBGrids, ADODB, ExtCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Panel1: TPanel;
    Button2: TButton;
    procedure FormCreate(Sender: TObject);
  private
        FLast: TWincontrol;
  public
    procedure AppMessage(var Msg: TMsg; var Handled: Boolean);
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.AppMessage(var Msg: TMsg; var Handled: Boolean);
var
  lCon: tControl;
  lCon2: tControl;
  lp: tpoint;
  lp2: tpoint;
  lc: tPoint;
  lGotLast: boolean;
  lRect: TRect;
  lDC: HDC;
  lPen: HPen;
begin
  if (Msg.Message = WM_LBUTTONDOWN) then
  begin
            lc:=Mouse.CursorPos;
            Handled:=true;
            lp:=ScreenToClient(lc);
            //get the control at this position
            lCon:=ControlAtPos(lp,true,true);
            //now need to descend through the controls until get to last control at mouse position
    if lCon is tWinControl then
    begin
                  lGotLast:=false;
                  while not lGotLast do
      begin
                              if lCon is tWincontrol then
          begin
            lp:=(lCon as TWinControl).ScreenToClient(lc);
            lCon2:=(lCon as TWinControl).ControlatPos(lp,true,true);
            if lCon2=nil then
              lGotLast:=true
            else
              lCon:=lCon2;
          end
          else
                lGotLast:=true;
                  end;
    end;
            if lCon<>nil then
    begin
      lp:=(lCon as TWinControl).Clienttoscreen(Point(0,0));
      lp2:=(lCon as TWinControl).Parent.Clienttoscreen(Point(0,0));
      lRect.Left:=lp.x-lp2.x-4;
      lREct.Top:=lp.y-lp2.y-4;
      lRect.Right:=lRect.Left+(lCon as TWinControl).Width+4;
      lRect.Bottom:=lRect.Top+(lCon as TWinControl).Height+4;
      if assigned(FLast) then
            FLast.Repaint;
      lDC:=GetDC((lCon as TWinControl).Parent.Handle);
      lPen:=CreatePen(PS_SOLID,4,clRed);
      SelectObject(lDc,lpen);
      Rectangle(lDC,lREct.Left,lRect.Top,lrect.Right,lrect.Bottom);
                  Handled:=true;
      FLast:=(lCon as TWinControl).Parent;
    end;
  end;
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
      Application.OnMessage:=AppMessage;
end;

end.


------------------------------------------Form Code--------------------------------------

object Form1: TForm1
  Left = 1347
  Top = 231
  Width = 696
  Height = 480
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 13
  object Button1: TButton
    Left = 64
    Top = 156
    Width = 75
    Height = 25
    Caption = 'Button1'
    TabOrder = 0
  end
  object Panel1: TPanel
    Left = 144
    Top = 304
    Width = 513
    Height = 129
    Caption = 'Panel1'
    TabOrder = 1
    object Button2: TButton
      Left = 36
      Top = 32
      Width = 75
      Height = 25
      Caption = 'Button2'
      TabOrder = 0
    end
  end
end

Note this is using the Appmessage code and the left click event so the control will be highlighted when you click on it but you can change how this works by modifying the message that is being responded to

Regards
0
pcsentinelCommented:
How did you get on, if your having probs let me have ur controlundermouse code

Regards
0
voodoo22Author Commented:
I understand why it was not working before because we are not really thinking the same way and I did not know your code only worked for controls on the form and not system wide which is what I am looking for.

Basically I want it to add the border to ANY window/control on my computer (not just the controls on the form)  when i mouseover it (clicking is not really an option) hope that helps clear things up.

Also......

if you ever used the snagit program I talked about above you would see exactly the effect I am trying to accomplish. There is another program call "spy & capture utility" which is tool that gives you information about the winows your mouse is over and this program also uses this method so if you can find that program then you can see what I am talking about as well.
0
pcsentinelCommented:
Ok this should work its a bit of a cheat as its using a timer in your app but it works.

put

   private
        FLast2: HWND;

in declarations

then add a timer to your app with an interval of 10 and on the timer put

var
  lp: TPoint;
  lWnd: HWnd;
  lRect: TRect;
  lRect2: TRect;
  lDC: HDC;
  lPen: HPen;
  lBrush: HBrush;
  lbd: tagLOGBRUSH;
begin
      GetCursorPos(lp);
  lWnd:=WindowFromPoint(lp);
            if (lWnd<>null) and (lWnd<>GetDesktopWindow) and (lWnd<>FLAst2) then
    begin
      InvalidateRgn(FLast2,0,true);
      UpdateWindow(FLast2);
      lRect.Left:=lp.x;
      lRect.Top:=lp.y;
      Windows.GetClientRect(lWnd,lRect);
      lRect2.Left:=0;
      lRect2.Top:=0;
      lRect2.Right:=lRect.Right-lRect.Left-8;
      lRect2.Bottom:=lRect.Bottom-lRect.Top-8;
      lDC:=GetDC(lWnd);
      lPen:=CreatePen(PS_SOLID,4,clRed);
      lbd.lbStyle:=BS_HOLLOW;
      lbd.lbColor:=clRed;
      lbd.lbHatch:=HS_CROSS;
     lBrush:=CreateBrushIndirect(lbd);
      SelectObject(lDc,lpen);
      SelectObject(lDc,lBrush);
      Rectangle(lDC,lREct.Left,lRect.Top,lrect.Right,lrect.Bottom);
      DeleteObject(lPen);
      DeleteObject(lBrush);
      FLast2:=lWnd;
    end;
end;
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
voodoo22Author Commented:
timer is fine and thx for the help
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.