Solved

Magnetic Windows

Posted on 2006-10-20
5
294 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
  • 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 250 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

Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

Join & Write a Comment

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.

760 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

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now