AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein GUI-Design mit VCL / FireMonkey / Common Controls Delphi Positionierung einer Form in Multimonitorumgebung
Thema durchsuchen
Ansicht
Themen-Optionen

Positionierung einer Form in Multimonitorumgebung

Ein Thema von Dalai · begonnen am 8. Aug 2015 · letzter Beitrag vom 16. Nov 2015
Antwort Antwort
Seite 1 von 3  1 23      
Benutzerbild von Dalai
Dalai

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

Positionierung einer Form in Multimonitorumgebung

  Alt 8. Aug 2015, 13:31
Hallo Leute,

hier ist schon wieder der ohne Lama .

Vorgestern ist mir eine Sache in meinen Total Commander Plugins aufgefallen: Die Positionierung der Formulare ist falsch, wenn sie in einer Multimonitorumgebung benutzt werden. Es werden alle davon auf dem linken Monitor plaziert, und zwar unabhängig davon, welcher der primäre Monitor ist. Interessanterweise trifft das nur auf das mit XE2 erstellte Kompilat zu. Die mit Delphi 5 erstellte DLL positioniert alle Forms immer auf dem aktiven Monitor, d.h. dort, wo sich Total Commander befindet.

Nun hab ich mir natürlich die Eigenschaft TForm.DefaultMonitor angeschaut und damit ein bisschen rumgespielt, aber der Satz
Zitat:
Note: DefaultMonitor has no effect if the application does not have a main form
ist wohl ernstzunehmen, auch wenn mich wundert, dass es im alten Delphi funktioniert, obwohl dieser Hinweis auch dort schon zu finden ist.

Frage:
An welcher Schraube muss ich drehen, um eine Änderung der Formpositionierung zu erreichen? Geht das ohne manuelle Plazierung der Formulare oder muss ich wirklich alles von Hand machen?

MfG Dalai
  Mit Zitat antworten Zitat
Benutzerbild von haentschman
haentschman
Online

Registriert seit: 24. Okt 2006
Ort: Seifhennersdorf / Sachsen
5.388 Beiträge
 
Delphi 12 Athens
 
#2

AW: Positionierung einer Form in Multimonitorumgebung

  Alt 8. Aug 2015, 14:15
Hallo...

Ich rate mal:
Stelle mal die PlugInForm auf poMainFormCenter z.B. Ich tippe sie steht auf poDesigned. Da dein Plugin vom TotalCommander geladen wird sollte "MainForm" TotalCommander heißen.
  Mit Zitat antworten Zitat
Benutzerbild von Dalai
Dalai

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

AW: Positionierung einer Form in Multimonitorumgebung

  Alt 8. Aug 2015, 14:55
TForm.Position steht auf poOwnerFormCenter. poScreenCenter hab ich ebenfalls probiert, aber das ändert nichts. Auch poMainFormCenter bringt nichts, weil es keine MainForm gibt (Application.MainForm ist nicht zugewiesen, also vermutlich nil).

MfG Dalai
  Mit Zitat antworten Zitat
Perlsau
(Gast)

n/a Beiträge
 
#4

AW: Positionierung einer Form in Multimonitorumgebung

  Alt 8. Aug 2015, 16:08
Also ich merke mir immer die linke obere Ecke einer Form, deren Position ich speichern will, damit hatte ich noch nie Probleme. Wenn dein Haupt-Monitor eine horizontale Bildschirmauflösung von 1920 hat und der zweite rechts davon positioniert ist, dann ist das erste Pixel des zweiten Monitors in der Spalte 1920.
  Mit Zitat antworten Zitat
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
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#6

AW: Positionierung einer Form in Multimonitorumgebung

  Alt 8. Nov 2015, 00:23
Der richtige Zeitpunkt wäre wohl der erste Idle-Zustand nach dem OnShow
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
HolgerX

Registriert seit: 10. Apr 2006
Ort: Leverkusen
970 Beiträge
 
Delphi 6 Professional
 
#7

AW: Positionierung einer Form in Multimonitorumgebung

  Alt 8. Nov 2015, 10:30
Wenn ich ein 'OnAfterShow' benötige, dann sende ich im Show eine Message per PostMessage an die Form selber und kann dann in

procedure WndProc(var Message: TMessage); override;

darauf reagieren.

Bei OnIdle ist das Problem, das ich mir merken muss, das es das erste OnIdle nach dem Show ist, da OnIdle immer wieder aufgerufen wird, wenn nichts zu tun ist.

Durch das Postmessage am Ende von OnShow werden zunächst noch alle Windows-Messages verarbeitet und dann kommt erst deine eigene 'OnAfterShow', so dass Du sicher sein kannst, dass alle Messages beim Formularanzeigen, wie z.B. die korrekte Anzeige aller Controlls abgeschlossen ist.

Ach..
Und bei OnActivate hatte ich die Probleme, das es manchmal gar nicht aufgerufen wurde oder wenn die Form mit Show statt ShowModal angezeigt wurde bei jedem Formularwechsel wieder aufgerufen wurde..

Geändert von HolgerX ( 8. Nov 2015 um 10:34 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Dalai
Dalai

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

AW: Positionierung einer Form in Multimonitorumgebung

  Alt 8. Nov 2015, 14:25
Ich wollte eigentlich auf etwas anderes hinaus: Wenn ich mich an ein Event (OnActivate, OnShow) hänge, das von außen gesetzt werden kann - entweder im Objektinspektor oder im Code - wird der Code zur Plazierung des Forms nicht ausgeführt, und zwar ohne, dass es eine Warnung gibt oder sonstwas.

Daher habe ich etwas tiefer gegraben und bin fündig geworden:
Delphi-Quellcode:
TTotalCmdWfxForm = class(TForm)
  private
    { Handle to TC's main window }
    FhTotalCmd : HWND;
    { Has this form been centered on the active screen? }
    FCentered : Boolean;
    function GetMonitorOfParent(const AParent: HWND = 0): TMonitor;
    procedure CenterOnMonitor(const AMonitor: TMonitor;
    procedure CMShowingChanged(var Message: TMessage); message CM_SHOWINGCHANGED;
  end;


procedure TTotalCmdWfxForm.CMShowingChanged(var Message: TMessage);
var Lmon: TMonitor;
begin
    inherited;
    if Self.Showing then begin
        if NOT FCentered then begin
            if (Screen.MonitorCount > 1) then begin
                Lmon:= GetMonitorOfParent(FhTotalCmd);
                CenterOnMonitor(Lmon);
            end;
            FCentered:= True;
        end;
    end;
end;
Anscheinend ist es so (ausgehend von gezielt gesetzten Breakpoints auf das inherited; und die nachfolgende Zeile), dass die Nachricht einerseits zum richtigen Zeitpunkt und andererseits selten genug gesendet wird, so dass es nicht stört.

Offenbar ist es auf diese Weise möglich, in der Basisklasse privat deklarierte Messages zu überschreiben.

Sofern es keine (begründeten) Einwände gegen diese Variante gibt, werde ich es dabei belassen. Danke auf jeden Fall an alle Beteiligten!

MfG Dalai
  Mit Zitat antworten Zitat
delnu
(Gast)

n/a Beiträge
 
#9

AW: Positionierung einer Form in Multimonitorumgebung

  Alt 12. Nov 2015, 12:20
Weil es bei mir dasselbe Problem gibt, habe ich das aus dem letzten Beitrag mal ausprobiert, bekomme aber Fehlermeldungen.

procedure CenterOnMonitor(const AMonitor: TMonitor;
Da fehlt die Klammer vor dem Semikolon.

function GetMonitorOfParent(const AParent: HWND = 0): TMonitor;
procedure CenterOnMonitor(const AMonitor: TMonitor);

-> Ungenügende Forward- oder External-Deklaration.

Habe ich irgendwas übersehen?

Wenn ich das mit dem weiter vorne geposteten Quelltext kombiniere, gibt es andere Fehlermeldungen über fehlende "Bezeichner" :

in "GetMonitorOfParent" : MonitorFromWindow, mdNearest ( Result:= Screen.MonitorFromWindow(AParent, mdNearest); )
in "CenterOnMonitor" : WorkAreaRect, width und height ( Lrect:= AMonitor.WorkAreaRect; Lwidth:= Lrect.Width; Lheight:= Lrect.Height; )

Könntest Du bitte mal einen kompletten Quellcode eines (ansonsten leeren) Basisformulars veröffentlichen, bei dem der TC das Formular wirklich im gerade aktiven Fenster startet ?

Danke im Voraus.

Ach, ich sehe gerade bei dem älteren Beitrag "Hier ein Auszug (ohne die ganzen Ergänzungen für alte Delphis):"

Wie sehen diese "ganzen Ergänzungen" denn für Delphi 5 aus ?
  Mit Zitat antworten Zitat
Benutzerbild von Dalai
Dalai

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

AW: Positionierung einer Form in Multimonitorumgebung

  Alt 12. Nov 2015, 13:38
Weil es bei mir dasselbe Problem gibt, habe ich das aus dem letzten Beitrag mal ausprobiert, bekomme aber Fehlermeldungen.

procedure CenterOnMonitor(const AMonitor: TMonitor;
Da fehlt die Klammer vor dem Semikolon.
Ja, sorry, das kommt von zuviel Copy'n'Paste meinerseits....

Zitat:
Könntest Du bitte mal einen kompletten Quellcode eines (ansonsten leeren) Basisformulars veröffentlichen, bei dem der TC das Formular wirklich im gerade aktiven Fenster startet ?
Sicher. Gestern habe ich daraus eine Klasse mit erweiterten Methoden gebastelt. Da das etwas mehr als nur ein paar Funktionen sind, hänge ich mal die komplette Unit an. Ich hoffe, da sind nicht allzu grobe Schnitzer drin .

Benutzung der Klasse dann z.B. so:
Delphi-Quellcode:
uses ..., TotalCmdGUI;

type
  TfmSvcProperties = class(TTotalCmdWfxForm)
   //[...]
  end;

implementation

procedure PluginShowForm(const AhParent: HWND);
var fmSvcProperties: TfmSvcProperties;
    Lmon: TFormMonitor;
begin
    fmSvcProperties:= TfmSvcProperties.Create(nil, AhParent);
    try
        case IniFile.Monitor of
          0..4: Lmon:= TFormMonitor(IniFile.Monitor);
          else Lmon:= fmActive;
        end;
        fmSvcProperties.ShowModal(Lmon);
    finally
        FreeAndNil(fmSvcProperties);
    end;
end;
Wenn du die Methode Init nicht brauchst, kannst du auch direkt von TFormEx ableiten (TTotalCmdWfxForm ist eh nur eine leere Hülle).

Zitat:
Wie sehen diese "ganzen Ergänzungen" denn für Delphi 5 aus ?
Hier geht's in erster Linie um Funktionen wie TMonitor.GetWorkareaRect, die nötig ist, um den Arbeitsbereich des jeweiligen Monitors zu ermitteln (statt einfach nur die volle Auflösung).

MfG Dalai
Angehängte Dateien
Dateityp: pas TotalCmdGUI.pas (7,1 KB, 11x aufgerufen)

Geändert von Dalai (12. Nov 2015 um 13:45 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 15:22 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