?
Solved

Magnetic Windows

Posted on 2006-10-20
5
Medium Priority
?
338 Views
Last Modified: 2010-04-05
Hi,
I want to write a program that will dock and or align (left,right,top,bottom) with another application. Much like the menus in Photoshop how they dock and align with each other. However, my application needs to do this with another running application not of my creation.

So the use case is as follows:

1- Program Is launched
2- Program Detects that 3rd party application is running
3- Based on the third party location on the screen my application will align itself to the left or right hand side of the 3rd party application
4- Based on user settings, this shouls work for top and bottom as well where my program aligns with the bottom or top of the 3rd party applications form.

This of this as making a docking toolbar for notepad. How would you make a bar doc with the window of notepad..?

Thanks

Q2
0
Comment
Question by:quantum2
[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
  • 2
  • 2
5 Comments
 
LVL 17

Expert Comment

by:mokule
ID: 17777417
It's easy if You want only to place program window at startup.
You must first launch notep to see how it works.

procedure TForm1.FormCreate(Sender: TObject);
var
  h: THandle;
  r: TRect;
begin
  h := FindWindow('notepad',nil);
  if h <> 0 then
    begin
    getWindowRect(h,r);

    Left := r.Right;
    Top := r.Top;
    Height := r.Bottom - r.Top;
{
// this code is to place window at the bottom
    Left := r.Left;
    Top := r.Bottom;
    Width := r.Right - r.Left;
}
    end;
end;
0
 
LVL 17

Expert Comment

by:mokule
ID: 17777466
If You want to keep moving with the other window You can do like this.
That is use timer.
Maybe not the most beautifull, but working.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls;

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    procedure PlaceWindow;
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  PlaceWindow;
  Timer1.Interval := 10;
end;

procedure TForm1.PlaceWindow;
var
  h: THandle;
  r: TRect;
begin
  h := FindWindow('notepad',nil);
  if h <> 0 then
    begin
    getWindowRect(h,r);

    Left := r.Right;
    Top := r.Top;
    Height := r.Bottom - r.Top;
{
    Left := r.Left;
    Top := r.Bottom;
    Width := r.Right - r.Left;
}
    end;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  PlaceWindow;
end;

end.
0
 
LVL 1

Author Comment

by:quantum2
ID: 17778854
Ideally, the program would "attach" to the parent application (in this case Notepad) if it was within 10 pixels of the notepad.exe window. Otherwise it could be placed anywhere and I could remember its previous location when I start the app.

Do you have an idea on how to make it dock like that (when the right side of my form is 10 pixels from the left of the Notepad window) and the same for the other corresponding sides..?

I will try what you have already sent in...

Thanks

Q2
0
 
LVL 28

Accepted Solution

by:
TName earned 1000 total points
ID: 17785600
>Ideally, the program would "attach" to the parent application (in this case Notepad) if it was within 10 pixels of the notepad.exe window. Otherwise it could be placed anywhere and I could remember its previous location when I start the app.


Hi, here's a little application that does this (as I understand it).

Mokule showed you the correct way to go, and the PlaceWindow procedure just adapts/expands his original solution.

You should save the project before testing, as it needs to write the settings file somewhere where it can find it.
I've set the "docking distance" to 20 px, if you want it 10 just change the value of DOCKING_DIST.
And set SizeToTarget to false if you don't want the window to resize when docking.
The window docks when one side is within the range of -x to +x from the target applications border. If you want it to only dock if it's x pixels *outside* the other window, just get rid of Abs().



unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;


const DOCKING_DIST:Integer=20;
const SCREEN_MARGIN_DIST=40;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  private
    SetSL:TStringList;
    TargetApp:String;
    SizeToTarget:Boolean;
    procedure WMNCLButtonDown(var Message: TWMNCLButtonDown); message WM_NCLBUTTONDOWN;
    function LoadSettingsFile(SL:TStringList): Boolean;
    function SaveSettingsFile(SL:TStringList): Boolean;
    procedure PlaceWindow;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
i:Integer;
begin
  SizeToTarget:=True;
  SetSL:=TStringList.Create;
  SetSL.Clear;
  TargetApp:='Notepad';
  if LoadSettingsFile(SetSL) then begin
      try
      if SetSL[0]<>'' then
        TargetApp:=SetSL[0];
      Left:=StrToInt(SetSL[1]);
      Top:=StrToInt(SetSL[2]);
      Width:=StrToInt(SetSL[3]);
      Height:=StrToInt(SetSL[4]);
      except
        //
      end;
  end;
end;

function TForm1.LoadSettingsFile(SL:TStringList): Boolean;
var
  SetFile: TMemoryStream;
  SetFileName: String;
begin
  Result := False;
  SetFile:=TMemoryStream.Create;
  try
    SetFileName:= ChangeFileExt(Application.ExeName, '.stg');
    if FileExists(SetFileName) then begin
      SetFile.LoadFromFile(SetFileName);
      SL.LoadFromStream(SetFile);
      DeleteFile(SetFileName);
      Result := True;
    end;
  finally
    SetFile.Free;
  end;
end;

function TForm1.SaveSettingsFile(SL:TStringList): Boolean;
var
  SetFile: TMemoryStream;
  SetFileName: String;
begin
  Result := False;
  SetFile:=TMemoryStream.Create;
  try
    SetFileName:= ChangeFileExt(Application.ExeName, '.stg');
    SL.SaveToStream(SetFile);
    SetFile.SaveToFile(SetFileName);
    Result := True;
  finally
    SetFile.Free;
  end;
end;

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  SetSL.Clear;
  SetSL.Add(TargetApp);
  SetSL.Add(IntToStr(Form1.Left));
  SetSL.Add(IntToStr(Form1.Top));
  SetSL.Add(IntToStr(Form1.Width));
  SetSL.Add(IntToStr(Form1.Height));
  SaveSettingsFile(SetSL);
  SetSL.Free;
end;

procedure TForm1.WMNCLButtonDown(var Message: TWMNCLButtonDown);
begin
   inherited;
   PlaceWindow;
end;

procedure TForm1.PlaceWindow;
var
  h: THandle;
  r: TRect;
  tempTop:Integer;
begin
  h := FindWindow(PAnsiChar('Notepad'),nil);
  if h <> 0 then begin
    getWindowRect(h,r);
    if Abs(r.Right-Left)<=DOCKING_DIST then begin
      Left := r.Right;
      Top := r.Top;
      if SizeToTarget then
        Height:=r.Bottom-r.Top;
    end
    else begin
      if (Abs(r.Bottom-Top)<=DOCKING_DIST) and
         (r.Bottom<Screen.Height-SCREEN_MARGIN_DIST) then begin
        Top := r.Bottom;
        Left:=r.Left;
        if SizeToTarget then
          Width:=r.Right-r.Left;
      end
      else begin
        if (Abs(Left+Width-r.Left)<=DOCKING_DIST) and
           (r.Left>SCREEN_MARGIN_DIST) then begin
          Left:=r.Left-Width;
          Top:=r.Top;
          if SizeToTarget then
            Height:=r.Bottom-r.Top;
         end
         else begin
            if (Abs(Top+Height-r.Top)<=DOCKING_DIST) and
               (r.Top<Screen.Height-SCREEN_MARGIN_DIST) then begin
               if Height<r.Top then
                  Top:=r.Top-Height
               else
                  Top:=0;
               Left:=r.Left;
               if SizeToTarget then
                 Width:=r.Right-r.Left;
            end;
         end;
      end;
    end;
  end;
end;

end.

0
 
LVL 1

Author Comment

by:quantum2
ID: 17840524
Thanks for the help. Both solutions did indeed work. Mokule, I will create a question for you to award some points. I do appreciate the help from both of you

-Q2
0

Featured Post

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.

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…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Michael from AdRem Software outlines event notifications and Automatic Corrective Actions in network monitoring. Automatic Corrective Actions are scripts, which can automatically run upon discovery of a certain undesirable condition in your network.…
Michael from AdRem Software explains how to view the most utilized and worst performing nodes in your network, by accessing the Top Charts view in NetCrunch network monitor (https://www.adremsoft.com/). Top Charts is a view in which you can set seve…
Suggested Courses
Course of the Month13 days, 1 hour left to enroll

777 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