Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Eigenes globales Andockprogramm - Warum flimmert es? (https://www.delphipraxis.net/45973-eigenes-globales-andockprogramm-warum-flimmert-es.html)

MisterNiceGuy 15. Mai 2005 21:42


Eigenes globales Andockprogramm - Warum flimmert es?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hi ich hab ein Programm angefangen, dass das Fenster, das den Focus hat an den Bildschirmrand andocken soll. An den Rändern klappt es schon, aber will ich es in die Ecke verschieben, dann
"flimmert" es, er verändert seine Position also immer sehr schnell.

Bein manchen Fenstern wird die Breite verändert, was ich ebenfalls nicht verstehe.

Hier der QT
Delphi-Quellcode:
procedure TForm1.Timer1Timer(Sender: TObject);
var
  hWindow: HWnd;
  r:      TRect;
begin
  if checkbox1.Checked = false then exit;
  hWindow := GetForegroundWindow;
  GetWindowRect(hWindow, r);
  //Linker Rand
  if (r.Left <= spinedit1.Value) AND (r.Left >= -spinedit1.Value)
    then MoveWindow(hwindow,0,r.Top,screen.Width-r.left-(screen.Width-r.right),screen.Height-r.top-(screen.Height-r.Bottom),True);
  //Rechter Rand
  if (r.Right >= (screen.Width-spinedit1.Value)) AND (r.Right <= (screen.Width + spinedit1.Value))
    then MoveWindow(hwindow,screen.Width-(screen.Width-r.left-(screen.Width-r.right)),r.Top,screen.Width-left-(screen.Width-r.right),screen.Height-r.top-(screen.Height-r.Bottom),True);
  //Oben
  if (r.Top <= spinedit1.Value) AND (r.Top >= -spinedit1.Value)
    then Movewindow(hwindow,r.Left,0,screen.Width-r.left-(screen.Width-r.right),screen.Height-r.top-(screen.Height-r.Bottom),True);
  //Unten
  if (r.Bottom >= (screen.height-spinedit1.Value)) AND (r.Bottom <= (screen.Height + spinedit1.Value))
    then MoveWindow(hwindow,r.Left,screen.Height-(screen.Height-r.top-(screen.Height-r.bottom)),screen.Width-left-(screen.Width-r.right),screen.Height-r.top-(screen.Height-r.Bottom),True);
end;

alcaeus 15. Mai 2005 22:24

Re: Eigenes globales Andockprogramm - Warum flimmert es?
 
Hallo MisterNiceGuy,

also dein Programm macht bei mir ueberhaupt nichts. Ich hab kurz ein Form gesehn, und das war anschliessend auch schon wieder weg. Der Prozess war nachher auch nicht mehr da. Eventuell solltest du mal sehn was da los ist.

Greetz
alcaeus

mirage228 16. Mai 2005 07:40

Re: Eigenes globales Andockprogramm - Warum flimmert es?
 
Zitat:

Zitat von alcaeus
Hallo MisterNiceGuy,

also dein Programm macht bei mir ueberhaupt nichts. Ich hab kurz ein Form gesehn, und das war anschliessend auch schon wieder weg. Der Prozess war nachher auch nicht mehr da. Eventuell solltest du mal sehn was da los ist.

Greetz
alcaeus

Hi,

dieses Phänomen kann ich bestätigen. Vielleicht kannst Du uns etwas mehr Source zur Verfügung stellen - der Fehler liegt wohl wo anders.

mfG
mirage228

tommie-lie 16. Mai 2005 08:40

Re: Eigenes globales Andockprogramm - Warum flimmert es?
 
Also wenn mir in einem Delphi-vs-C++-Flameware nochmal irgendjemand mit dem Argument "Delphicode ist viel übersichtlicher" ankommen sollte, kriegt er diesen Link hier rechts und links um die Ohren gehauen :mrgreen:

So, schau'n mer ma', wat det hier iss. Man nehme an, du willst das Fenster oben links andocken und es befindet sich gerade im Schwellwertbereich.
Delphi-Quellcode:
  hWindow := GetForegroundWindow;
  GetWindowRect(hWindow, r);
{
  Hier ist in r also die Position des Fensters, noch mit kleinem Rand nach oben und nach links.
}

  //Linker Rand
  if (r.Left <= spinedit1.Value) AND (r.Left >= -spinedit1.Value)
    then MoveWindow(hwindow,0,r.Top,
{
  Die neue X-Position ist 0, die Y-Position bleibt so. Erstma nix falsches.
}

  //Oben
  if (r.Top <= spinedit1.Value) AND (r.Top >= -spinedit1.Value)
    then Movewindow(hwindow,r.Left,0
{
  Nanu, r.Left enthält doch nicht 0. Hier setzt du die X-Position also wieder etwas vom Rand weg, dafür aber die Y-Position auf 0.
}
Also ich weiß ja nicht, wie oft dein Timer aufgerufen wird, aber wenn du mehrere Mal pro Sekunde die Position auf zwei völlig verschiedene Werte setzt, meinst du da nicht auch, daß es flackert? :zwinker:

By the way: 'n Hook auf WM_MOVING wäre vielleicht etwas eleganter als ein Timer, der sich jedes Mal das Fenster zu Fuß holt. Ich habe das damals mal für eigene Fenster geschrieben, die an anderen Fenstern der gleichen Anwendung andocken sollten. Dabei habe ich das in lParam enthaltene Rect solange verändert, bis es mir gefiel und dann an die Message zurückgegeben. Windows hat davon also mehr oder weniger gar nichts mitgekriegt, und geflimmert hat's daher auch nicht ;-)

MisterNiceGuy 16. Mai 2005 09:20

Re: Eigenes globales Andockprogramm - Warum flimmert es?
 
Hi also erstmal hab ich das noch ein bisschen übersichtlicher gemacht indem ich die Breite und Höhe des Fensters vorher zu berechne.
Delphi-Quellcode:
procedure TForm1.Timer1Timer(Sender: TObject);
var
  hWindow : HWnd;
  r      : TRect;
  Breite : Integer;
  Hoehe  : Integer;
begin
  //Wenn nicht aktiviert, dann verlasse
  if checkbox1.Checked = false then exit;
  //Holfe Handle und Position des aktiven Fensters
  hWindow := GetForegroundWindow;
  GetWindowRect(hWindow, r);
  //Berechnen von Breite und Höhe
  Breite := screen.Width-r.left-(screen.Width-r.right);
  Hoehe := screen.Height-r.top-(screen.Height-r.Bottom);
  //Linker Rand
  if (r.Left <= spinedit1.Value) AND (r.Left >= -spinedit1.Value)
    then MoveWindow(hwindow,0,r.Top,Breite,Hoehe,True);
  //Rechter Rand
  if (r.Right >= (screen.Width-spinedit1.Value)) AND (r.Right <= (screen.Width + spinedit1.Value))
    then MoveWindow(hwindow,screen.Width-Breite,r.Top,Breite,Hoehe,True);
  //Oben
  if (r.Top <= spinedit1.Value) AND (r.Top >= -spinedit1.Value)
    then Movewindow(hwindow,r.Left,0,Breite,Hoehe,True);
  //Unten
  if (r.Bottom >= (screen.height-spinedit1.Value)) AND (r.Bottom <= (screen.Height + spinedit1.Value))
    then MoveWindow(hwindow,r.Left,screen.Height-Hoehe,Breite,Hoehe,True);
end;
@mirage228: Das ist der ganze Code, der Rest ist nur noch das Schließen der Form.

@alcaeus: Tut mir leid, das kann ich absolut nicht nachvollziehen.

@Tommie-lie: Wieso wird r noch ein kleiner Rand nach oben und links angehängt???
Das wusste ich nicht.

P.S. Darauf, dass ich lParam verändern muss hab ich schon rausgefunden, aber mir hat keiner sagen können wie ich das mache, deswegen bin ich auf die Timermethode umgestiegen.

tommie-lie 16. Mai 2005 09:41

Re: Eigenes globales Andockprogramm - Warum flimmert es?
 
Zitat:

Zitat von MisterNiceGuy
@Tommie-lie: Wieso wird r noch ein kleiner Rand nach oben und links angehängt??? Das wusste ich nicht.

Es wird kein Rand angehangen. Aber r ist doch die Position des Fensters, bevor du sie änderst. Es enthält also das Fenster mit kleinem Rand zum linken und oberen Bildschirmrand, denn r änderst du ja später nicht mehr. Wenn nur eine der if-Abfragen durchlaufen wird, stimmt alles. Sobald du aber zwei if-Abfragen durchläufst, benutzt du beim ersten Mal r, beim zweiten Mal aber auch, und dadurch änderst du die Position zweimal auf zwei unterschiedliche Werte, das Fenster springt also hin und her. Und das ist vermutlich, was du als Flackern wahrnimmst.

Zitat:

Zitat von MisterNiceGuy
P.S. Darauf, dass ich lParam verändern muss hab ich schon rausgefunden, aber mir hat keiner sagen können wie ich das mache, deswegen bin ich auf die Timermethode umgestiegen.

Ich hab' mal den Quellcode rausgekramt:
Delphi-Quellcode:
type
  TfrmPlaylist = TForm...
  private
    LastPosition: TRect;
    RealPosition: TRect;
    Position: PRect;
    procedure FormMoving(var Message: TMessage); message WM_MOVING;
  end;

procedure TfrmPlaylist.FormMoving(var Message: TMessage);
begin
  Position := PRect(Message.lParam);

  // tracking of the window's real position
  RealPosition.Left := RealPosition.Left + (Position.Left - LastPosition.Left);
  RealPosition.Top := RealPosition.Top + (Position.Top - LastPosition.Top);
  RealPosition.Right := RealPosition.Left + Width;
  RealPosition.Bottom := RealPosition.Top + Height;

  // make changes from the last event undone
  Position.Top := RealPosition.Top;
  Position.Left := RealPosition.Left;

  DockingSite := dsNone;
  // do we have to do something?
  if RectIntersect(frmMain.RealPosition, RealPosition, 20) then
  begin
    // first we look at the single edges
    if Abs(RealPosition.Left - (frmMain.RealPosition.Right)) <= 20 then
    begin
      Position.Left := frmMain.RealPosition.Right;
      DockingSite := dsVertEdge;
    end;

    if Abs(RealPosition.Top - (frmMain.RealPosition.Bottom)) <= 20 then
      Position.Top := frmMain.RealPosition.Bottom;
      DockingSite := dsHorzEdge;
    end;

    if Abs(RealPosition.Right - (frmMain.RealPosition.Left)) <= 20 then
    begin
      Position.Left := frmMain.RealPosition.Left - Width;
      DockingSite := dsVertEdge;
    end;

    if Abs(RealPosition.Bottom - (frmMain.RealPosition.Top)) <= 20 then
    begin
      Position.Top := frmMain.RealPosition.Top - Height;
      DockingSite := dsHorzEdge;
    end;

  // Eigentlich kamen hier noch andere Feinheiten, die aber nix mit dem Problem zu tun hatten. Eye candy also ;-)
  // Am Ende wird natürlich noch die Größe des Rects an mein Fenster angepasst, weil ich nur die Top/Left-Werte verändere
  end;
end;
Du siehst, lParam enthält den Pointer und ich ändere das Rect, was dahinter ist, und kehre dann einfach zurück. Windows bearbeitet dann die WM_MOVING-Message weiter, und zwar mit den von mir korrigierten Werten, als ob nichts gewesen ist.

MisterNiceGuy 16. Mai 2005 09:52

Re: Eigenes globales Andockprogramm - Warum flimmert es?
 
Was ist den PRect für ein Typ? Die DelphiHilfe kennt das nicht. Ich habs jetzt so gelöst, dass ich nach jedem Andocken die Werte der Applikation erneut abfrage.
Jetzt wüsste ich gerne noch, wie ich die Windowsmessage hooke.
WM_MOVING oder WM_POSITIONCHANGED ist bestimmt am besten, nur wie mache ich das?

tommie-lie 16. Mai 2005 10:42

Re: Eigenes globales Andockprogramm - Warum flimmert es?
 
Zitat:

Zitat von MisterNiceGuy
Was ist den PRect für ein Typ?

Ein Pointer auf ein TRect: PRect = °TRect;
Mag sein, daß es nicht in der Hilfe steht, aber es sollte in den Stnadard-Units deklariert sein.

Zitat:

Zitat von MisterNiceGuy
Jetzt wüsste ich gerne noch, wie ich die Windowsmessage hooke.

Hier im Forum suchenhook und im Zweifelsfall http://www.assarbad.org


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:03 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz