Oprettet ons. d. 14. juli 2010 kl. 12:52:59

hugopedersen
hugopedersen (16.462 point. Point ude: 160)
www.hugopedersen.dk

Flytte form på 2 skærme

Jeg plejer at bruge nedenstående kode til at håndtere at brugere ikke flytter en form uden form skærmen.
Men nu er jeg blevet gjort opmærksom på et problem hvis man har 2 skærme:  det forhindrer også at man flytter formen til en anden skærm.

Nogen forslag til hvad jeg kan rette for at få den kringlet?
Jeg har dog ikke lige selv mulighed for at teste for nuværende da jeg kun har 1 skærm tilsluttet.

procedure TfrmMain.WMMoving(var message : TWMMoving);
var
  rec: ^TRect;
  wrk: TRect;
begin
  SystemParametersInfo(spi_getworkarea, 0, @wrk, 0);
  rec := Pointer(message.DragRect);
  if rec^.Left < wrk.Left then
    begin
      rec^.Right := rec^.Right - (rec^.Left - wrk.Left);
      rec^.Left := wrk.Left;
    end
  else if rec^.Right > wrk.Right then
    begin
      rec^.Left := rec^.Left - (rec^.Right - wrk.Right);
      rec^.Right := wrk.Right;
    end;
  if rec^.Top < wrk.Top then
    begin
      rec^.Bottom := rec^.Bottom - (rec^.Top - wrk.Top);
      rec^.Top := wrk.Top;
    end
  else if rec^.Bottom > wrk.Bottom then
    begin
      rec^.Top := rec^.Top - (rec^.Bottom - wrk.Bottom);
      rec^.Bottom := wrk.Bottom;
    end;
end;

Skrevet ons. d. 14. juli 2010 kl. 13:18:09| #1

martinlind
martinlind (60.334 point)
Hmm... det må alt andet lige være noget med

SystemParametersInfo(spi_getworkarea, 0, @wrk, 0);

der ikke får data på skræm to :-)

Skrevet tor. d. 15. juli 2010 kl. 06:52:43| #2

Det lyder meget plausibelt.

Skrevet lør. d. 17. juli 2010 kl. 12:55:26| #3

mbsnet
mbsnet (13.783 point)
www.mortenbs.com/
prøv med...:

function getWorkSpaceRect:tRect;
begin
result.left:=0;result.right:=getSystemMetrics(78);
result.top:=0;result.bottom:=getSystemMetrics(79);
offsetRect(result,getSystemMetrics(76),getSystemMetrics(77))
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
memo1.lines.clear;
with getWorkSpaceRect do begin
  memo1.lines.add('x1: '+intToStr(left));
  memo1.lines.add('y1: '+intToStr(top));
  memo1.lines.add('x2: '+intToStr(right));
  memo1.lines.add('y2: '+intToStr(bottom));
end
end;

Skrevet lør. d. 17. juli 2010 kl. 20:30:21| #4

Desværre har jeg ikke mulighed for at afprøve dit forslag før jeg vender tilbage efter ferie da jeg ikke er udstyret med mere end 1 skærm her hjemme.

Skrevet man. d. 02. august 2010 kl. 12:27:36| #5

mbsnet
mbsnet (13.783 point)
www.mortenbs.com/
ok, er nu ret sikker på den skulle fungere...

Skrevet tir. d. 03. august 2010 kl. 09:46:00| #6

Jeg har prøvet koden på 1 skærm og det ser ganske rigtigt ud til at virke. Men der er dog den lille catch at formen kan flyttes under taskbaren - det kan den ikke med den 'orginale' opskrift.

Skrevet tir. d. 03. august 2010 kl. 15:19:30| #7

mbsnet
mbsnet (13.783 point)
www.mortenbs.com/
Ok, kan godt se hvad du mener :-/ Der er også "screen.workAreaRect" men virker kun på den aktive skærm (virker dog med taskbar).

I forbindelse med Multiple Monitors, bør man nok loope "screen.monitors[]" via "screen.monitorCount", men prøv at hænge på et par dage mere....

Skrevet ons. d. 04. august 2010 kl. 22:48:48| #8

mbsnet
mbsnet (13.783 point)
www.mortenbs.com/
Har lavet en unit som kan styre en enkelt form på en bestemt måde...
Den kan kun bruges hvis formen ikke må fylde mere end 1 skærm af gangen... Den snapper formen til den skærm, som formen mest overlapper, tager også højde for taskbar (lidt)...

Hvis du ikke kan bruge det, kan du måske bruge rutinen til at finde taskbar'ens dimensioner...

//mbs

UNIT
unit multiMonCtrl;

interface

//MULTIPLE MONITOR CONTROL (for a single form)
//Keep form within multiple monitors screen boundaries.
//Works with monitors of different sizes and positions.
//IMPORTANT: Use only if form should stay at one screen of the time.

//HOW TO USE
//Simply add this unit into the form's uses-clause,
//and set reference to it in "FormCreate" like: mMonCtrl.ctrl:=self;

//Last updated: Aug 2010, mortenbs.com/it/delphi/multiple_monitors/

uses
windows,mbs,classes,controls;

type
//-----------------------------|----------------|----------------------|----------------------------
tMultiMonCtrl=class(tThread)
private
protected
  procedure execute;override;
public
  ctrl                        :tWinControl;    //The assigned form to manage.
  constructor create;reintroduce;
end;
//-----------------------------|----------------|----------------------|----------------------------

function taskBarRect(var r:tRect):boolean;
function findMostMonitor(aCtrl:tControl;out aMonitor:integer):boolean;
procedure keepFormWithinMostMonitor(aCtrl:tControl);
function mMonCtrl:tMultiMonCtrl;

implementation

uses
forms;

function taskBarRect(var r:tRect):boolean;
var h:hWnd;
begin h:=findWindow('Shell_TrayWnd',nil);
result:=h>0;if result then windows.getWindowRect(h,r)
end;

function findMostMonitor(aCtrl:tControl;out aMonitor:integer):boolean;
var i,x1,y1,x2,y2,w,h,sq,lSq:integer;
begin aMonitor:=-1;lSq:=0;
for i:=0 to screen.monitorCount-1 do with screen.monitors[i] do begin
  x1:=aCtrl.left;y1:=aCtrl.top;x2:=x1+aCtrl.width;y2:=y1+aCtrl.height;w:=0;h:=0;
if (x2>=left) and (x1<=left+width) and (y2>=top) and (y1<=top+height) then begin
  w:=x2-x1;if x1<left then dec(w,left-x1) else if x2>left+width then dec(w,x2-(left+width));
  h:=y2-y1;if y1<top then dec(h,top-y1) else if y2>top+height then dec(h,y2-(top+height));
  sq:=w*h;if sq>lSq then begin aMonitor:=i;lSq:=sq end
  end
end;result:=aMonitor>-1
end;

procedure keepFormWithinMostMonitor(aCtrl:tControl);
var aMonitor:integer;r:tRect;
begin
if findMostMonitor(aCtrl,aMonitor) then with screen.monitors[aMonitor] do begin
  //MONITOR
  if aCtrl.left+aCtrl.width>left+width then aCtrl.left:=(left+width)-aCtrl.width;if aCtrl.left<left then aCtrl.left:=left;
  if aCtrl.top+aCtrl.height>top+height then aCtrl.top:=(top+height)-aCtrl.height;if aCtrl.top<top then aCtrl.top:=top;
  //TASKBAR
  if taskBarRect(r) and (r.left>=left) and (r.right<=left+width) and (r.top>=top) and (r.bottom<=top+height) then
  if (r.top>screen.height div 2) then begin//LOWER TASKBAR
    if aCtrl.top+aCtrl.height>r.top then aCtrl.top:=r.top-aCtrl.height;
    if aCtrl.top<top then aCtrl.top:=top;
  end else //UPPER TASKBAR
    if aCtrl.top<r.top then aCtrl.top:=r.top;
end
end;

//--------------------------------------------------------------------------------------------------
//tMultiMonCtrl:

constructor tMultiMonCtrl.create;//reintroduce;
begin inherited create(true);freeOnTerminate:=true;
ctrl:=application.mainForm;resume
end;

procedure tMultiMonCtrl.execute;//override;
begin
while not terminated do begin
  if ctrl<>nil then try keepFormWithinMostMonitor(ctrl) except end;
  sleep(250)
end
end;

//--------------------------------------------------------------------------------------------------

var
fMultiMonCtrl:tMultiMonCtrl=nil;

function mMonCtrl:tMultiMonCtrl;
begin
if fMultiMonCtrl=nil then fMultiMonCtrl:=tMultiMonCtrl.create;
result:=fMultiMonCtrl
end;

initialization
mMonCtrl.resume;

finalization
if fMultiMonCtrl<>nil then begin
  if not fMultiMonCtrl.terminated then fMultiMonCtrl.terminate;
  fMultiMonCtrl:=nil
end;

end.


EKSEMPEL
unit Unit1;

interface

uses
  Windows, multiMonCtrl, Classes, Controls, Forms, ExtCtrls, StdCtrls;

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
  private
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
mMonCtrl.ctrl:=self
end;

end.

Skrevet ons. d. 04. august 2010 kl. 22:50:08| #9

mbsnet
mbsnet (13.783 point)
www.mortenbs.com/
p.s. fjern lige "mbs" fra uses... :-/

Skrevet tir. d. 10. august 2010 kl. 15:17:42| #10

Hov - den har jeg da ikke fået besked om at du har lagt op.
Den vil jeg prøve at se på i morgen tidlig.

Skrevet ons. d. 11. august 2010 kl. 11:52:40| #11

Kan ikke lige gennemskue om jeg kan bruge det da jeg på en maskine med bare 1 skærm kan flytte formen ud over kanten - og det må den ikke kunne.

Skrevet ons. d. 18. august 2010 kl. 21:03:31| #12

mbsnet
mbsnet (13.783 point)
www.mortenbs.com/
Det skal nok bygges sammen med "din"
procedure TfrmMain.WMMoving(var message : TWMMoving);
for at køre mere som ønsket.

Som jeg ser det, vil det i visse situationer forekomme at formen rager ud over indre kanter (hvis skærmstørrelserne afveksler i højde osv. /og hvordan de er placeret i forhold til hinanden).

Eksemplet jeg gav, tager højde for dette, men tillader dog ganske kort tid at formen er udenfor, og snapper så lidt "senere"...

...Men det skulle være muligt at formen holdes inden for de ydre kanter.

Er selv ret booket op i øjeblikket, men vil gerne prøve at se på det igen, hvis det ikke haster helt vildt..

Skrevet tor. d. 19. august 2010 kl. 06:52:00| #13

No problem - det er ikke en funktion der er mission critical for mig :-)

Skrevet tir. d. 07. september 2010 kl. 06:46:41| #14

mbsnet
mbsnet (13.783 point)
www.mortenbs.com/
Hej igen. Så fik jeg kigget lidt på sagen igen, og er kommet frem til følgende:

unit Unit1;

interface

uses
  windows, messages, classes, controls, graphics, forms;

type
  TForm1 = class(TForm)
  private
    procedure wmMoving(var aMsg:tWmMoving);message WM_MOVING;
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

const
DI_LEFT  = $01;
DI_RIGHT  = $02;
DI_TOP    = $03;
DI_BOTTOM = $04;

function findMostMonitor(x1,y1,x2,y2:integer;out aMon:integer;out r:tRect):boolean;
var i,w,h,sq,lSq:integer;
begin aMon:=-1;lSq:=0;
for i:=0 to screen.monitorCount-1 do with screen.monitors[i] do
  if (x2>=left) and (x1<=left+width) and (y2>=top) and (y1<=top+height) then begin
  w:=x2-x1;if x1<left then dec(w,left-x1) else if x2>left+width then dec(w,x2-(left+width));
  h:=y2-y1;if y1<top then dec(h,top-y1) else if y2>top+height then dec(h,y2-(top+height));
  sq:=w*h;if sq>lSq then begin aMon:=i;lSq:=sq end
  end;result:=aMon>-1;if result then r:=screen.monitors[aMon].workareaRect
end;

function hasMonitorAt(aDir:byte;aMon:integer;p,mP:pRect):boolean;
var i:integer;
begin result:=true;with screen do
for i:=0 to monitorCount-1 do if i<>aMon then with monitors[i].workareaRect do case aDir of
  DI_LEFT:  if (right<=mP^.left) and (top<=p.top) and (bottom>=p.bottom) then exit;
  DI_RIGHT: if (left>=mP^.right) and (top<=p.top) and (bottom>=p.bottom) then exit;
  DI_TOP:  if (bottom<=mP^.top) and (left<=p.left) and (right>=p.right) then exit;
  DI_BOTTOM:if (top>=mP^.bottom) and (left<=p.left) and (right>=p.right) then exit;
end;result:=false
end;

procedure TForm1.wmMoving(var aMsg:tWmMoving);
var aMon:integer;p:pRect;r:tRect;
begin
if not findMostMonitor(left,top,left+width,top+height,aMon,r) then exit;p:=aMsg.dragRect;
with p^ do begin
  if (left<r.left) and not hasMonitorAt(DI_LEFT,aMon,p,@r) then begin dec(right,left-r.left);left:=r.left end else
  if (right>r.right) and not hasMonitorAt(DI_RIGHT,aMon,p,@r) then begin dec(left,right-r.right);right:=r.right end;
  if (top<r.top) and not hasMonitorAt(DI_TOP,aMon,p,@r) then begin dec(bottom,top-r.top);top:=r.top end else
  if (bottom>r.bottom) and not hasMonitorAt(DI_BOTTOM,aMon,p,@r) then begin dec(top,bottom-r.bottom);bottom:=r.bottom end
end
end;


end.

Skrevet man. d. 13. september 2010 kl. 09:47:13| #15

Har desværre først haft tid til at se på det nu, men jeg kan ikke lige få det til at spille.

Har du det eksempel du har leget med som jeg evt. må få en kopi af?

oz8hp  snabelting  hotmail  punktum  com

Skrevet man. d. 13. september 2010 kl. 10:20:06| #16

mbsnet
mbsnet (13.783 point)
www.mortenbs.com/
Har ikke nogen udgående post server lige PT (profiber tilbyder ikke) men har forsøgt at tilføje dig til msn på den adresse du har oplyst på dit site (uden held). Men her er et midlertidigt link til projektet. http://www.mortenbs.com/ (...)

Denne gang har jeg ellers taget udgangspunkt i dit eget eksempel, hvor den nu undersøger, om der er "hul" til en parallel skærm ved de fire retninger... Har ikke testet med en enkelt skærm, men burde også fungere...

Skrevet man. d. 13. september 2010 kl. 10:26:50| #17

På Messenger skal du også bruge

oz8hp  snabelting  hotmail  punktum  com

Skrevet man. d. 13. september 2010 kl. 10:36:09| #18

Smid bare lige et svar her mbs

Skrevet man. d. 13. september 2010 kl. 10:51:49| #19


Skriv et indlæg




Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] [img]link til billede[/img]
Web- og emailadresser omdannes automatisk til links

Log ind

   

   

Seneste spørgsmål

Irriterende timeout i Delphi 7 på en win7 64 bits platform

Oprettet den 2. februar 2012 kl. 12.17
nca giver 60 point for svar | Giv et svar »

Manglende danske tegn

Oprettet den 24. januar 2012 kl. 16.12
hugopedersen giver 60 point for svar | Giv et svar »

Sikre mig at form er færdigoprettet

Oprettet den 24. januar 2012 kl. 10.01
hugopedersen giver 100 point for svar | Giv et svar »

Seneste guides

Installer win 7
Den gode bruger


   




Tips & Tricks fra PC World

Teaser billede

Her er fem sjove danske websider du skal kende

Trænger dine lattermuskler til en omgang fitness på dansk? Vi viser vej til fem websider fyldt med humor og vanvittig satire.


Anmeldelser fra PC World

Teaser billede

Test: Denne super-tablet er iPads hårdeste konkurrent

Eee Pad Transformer Prime er frygtindgydende med sin quadcore processor og evne til at trylle sig om til bærbar. Apple bør kigge i bagspejlet, for Asus' tablet-pc kommer buldrende - og gør det...


Seneste blogindlæg

Teaser billede

Tvangslukke spørgsmål: Hvad er den bedste løsning?

Hej Vi har mange åbne spørgsmål på Eksperten. Vi ville gerne tvangslukke dem - så et spørgsmål efter f.eks. 6 måneder lukkes. Men der er et par uklarheder som ville være gode at få lidt input til:...


Nyheder fra PC World

Teaser billede

Nu kan du snart hente Windows 8

Den nye offentlige betaversion af Windows 8 er klar i denne måned.


Nyheder fra Computerworld

Teaser billede

Måske snart slut med Androids helt store problem

Android-platformen har længe været plaget af et særligt problem. Men måske er problemet nu ved at være elimineret.


Kurser
Samarbejdspartnere

Udgiver · © 2012 IDG Danmark A/S · Hørkær 18 · 2730 Herlev · Tlf.: 77 300 300 · Fax: 77 300 301 · Brug af personoplysninger