Einzelnen Beitrag anzeigen

Benutzerbild von Dalai
Dalai

Registriert seit: 9. Apr 2006
1.682 Beiträge
 
Delphi 5 Professional
 
#5

AW: Positionierung einer Form in Multimonitorumgebung

  Alt 7. Nov 2015, 22:50
Tut mir leid, dass ich so lange nichts von mir hören ließ. Es war zuviel Arbeit, und da musste sich dieses Privatprojekt hinten anstellen.

Heute kam ich wieder dazu, mich damit zu beschäftigen. Zuerst eine Korrektur: Es ist wohl anders als ich bisher annahm, dass die Forms nicht immer auf dem linken Monitor dargestellt werden sondern immer auf dem primären; ich hoffe, das ist diesmal richtig, denn momentan ist nicht hundertprozentig sicher, wie die Anordnung auf dem einen Rechner war, an dem mir die Sache überhaupt erst aufgefallen war.

Weiterhin ist es so, dass die Sache nicht nur dieses spezifische Projekt (Total Commander Plugin) betrifft sondern offenbar alle Delphi-Programme - nach einigen Tests mit meinen normalen Programmen erlaube ich mir, diese Behauptung aufzustellen. Das erste Form eines Delphi-Programms wird offenbar immer auf dem primären Monitor angezeigt. Soweit ist das ja auch in Ordnung. Aber bei Forms aus DLLs wird die Sache knifflig, vor allem dann, wenn man TApplication.MainForm und/oder TApplication.Handle nicht gesetzt hat - was in diesem Fall seine Gründe hat (für Hintergründe siehe Modales Fenster in DLL, Taskleiste).

Kommen wir zum Wesentlichen. Ich habe eine Möglichkeit gefunden, mein Ziel mit ein wenig Code zu erreichen. Hier ein Auszug (ohne die ganzen Ergänzungen für alte Delphis):
Delphi-Quellcode:
type
  TTotalCmdWfxForm = class(TForm)
  private
    { Handle to TC's main window }
    FhTotalCmd : HWND;
    function GetMonitorOfParent(const AParent: HWND = 0): TMonitor;
    procedure CenterOnMonitor(const AMonitor: TMonitor);
    procedure FormActivate(Sender: TObject);
  public
    procedure Init; virtual;
  end;
  


procedure TTotalCmdWfxForm.Init;
begin
    Self.OnActivate:= Self.FormActivate;
end;

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

function TTotalCmdWfxForm.GetMonitorOfParent(const AParent: HWND = 0): TMonitor;
begin
    Result:= Screen.MonitorFromWindow(AParent, mdNearest);
end;

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

procedure TTotalCmdWfxForm.CenterOnMonitor(const AMonitor: TMonitor);
var Lrect: TRect;
    Lwidth, Lheight: integer;
begin
    if AMonitor <> nil then begin
        Lrect:= AMonitor.WorkAreaRect;
        Lwidth:= Lrect.Width;
        Lheight:= Lrect.Height;
        Self.Left:= AMonitor.Left + ((Lwidth div 2) - (Self.Width div 2));
        Self.Top:= AMonitor.Top + ((Lheight div 2) - (Self.Height div 2));
    end;
end;

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

procedure TTotalCmdWfxForm.FormActivate(Sender: TObject);
var Lmon: TMonitor;
begin
    if (Screen.MonitorCount > 1) then begin
        Lmon:= GetMonitorOfParent(FhTotalCmd);
        CenterOnMonitor(Lmon);
    end;
end;
Hinweis: Der Wert von FhTotalCmd wird im Konstruktor gesetzt, der in obigem Code fehlt.

Was mit daran überhaupt nicht gefällt, ist die Benutzung des OnActivate-Ereignisses. Dummerweise setzt die VCL irgendwann im OnShow (SetVisible) die Position der Form um, so dass irgendwelche vorherigen Änderungen überschrieben werden. Ich muss also nach OnShow ansetzen; da kommt aber nur noch OnActivate, oder liege ich da falsch?

Hat dazu jemand Ideen?

MfG Dalai
  Mit Zitat antworten Zitat