?
Solved

Place a border around windows/controls on mouseover

Posted on 2005-03-28
11
Medium Priority
?
195 Views
Last Modified: 2010-04-05
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.
0
Comment
Question by:voodoo22
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 7
  • 4
11 Comments
 
LVL 11

Expert Comment

by:pcsentinel
ID: 13650331
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
 
LVL 11

Expert Comment

by:pcsentinel
ID: 13650360
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
 

Author Comment

by:voodoo22
ID: 13650517
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
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 11

Expert Comment

by:pcsentinel
ID: 13650852
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
 
LVL 11

Expert Comment

by:pcsentinel
ID: 13651230
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
 

Author Comment

by:voodoo22
ID: 13651247
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
 
LVL 11

Expert Comment

by:pcsentinel
ID: 13651374
-------------------------------------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
 
LVL 11

Expert Comment

by:pcsentinel
ID: 13652784
How did you get on, if your having probs let me have ur controlundermouse code

Regards
0
 

Author Comment

by:voodoo22
ID: 13653480
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
 
LVL 11

Accepted Solution

by:
pcsentinel earned 800 total points
ID: 13659989
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
 

Author Comment

by:voodoo22
ID: 13660204
timer is fine and thx for the help
0

Featured Post

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Visualize your data even better in Access queries. Given a date and a value, this lesson shows how to compare that value with the previous value, calculate the difference, and display a circle if the value is the same, an up triangle if it increased…
How to fix incompatible JVM issue while installing Eclipse While installing Eclipse in windows, got one error like above and unable to proceed with the installation. This video describes how to successfully install Eclipse. How to solve incompa…
Suggested Courses
Course of the Month14 days, 20 hours left to enroll

770 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question