Vollständige Sichtbarkeit eines Forms
Moin, Moin.
Ich arbeite abwechselnd mit einem Notebook und einem PC(mit 2 Monitoren). Da hat es genervt, dass die Wiederherstellung der letzten Fensterposition beim Wechsel von PC auf Notebook immer problematisch war - das hat ja nun mal leider keine 2 Bildschirme eingebaut :( Nun habe ich mich mal an einer endgültige Problemlösung versucht. Das Ergebnis sorgt nach erstem Test dafür, dass das Programmfenster vollständig sichtbar angezeigt wird, auch wenn aus der INI-Datei Koordinaten zur Positionierung gelesen wurden, mit der das Fenster in der aktuellen Monitorumgebung eigentlich nicht oder nicht vollständig sichtbar dargestellt werden könnte. 1 - Auf welchem Monitor wird Form dargestellt? Ermittelt, auf welchem Monitor das Form angezeigt wird. Bildet das Form auf Multi-Monitorsystemen Schnittflächen mit mehreren Monitoren, wird derjenige Monitor zurückgeliefert, der die größte Schnittfläche mit dem Form hat. Ist das Form aufgrund einer völlig abweichenden Monitorkonfiguration auf keinem aktuell verfügbaren Monitor sichtbar, wird als Ergebnis der Primärmonitor zurückgeliefert.
Delphi-Quellcode:
2 - Ist Form auf Monitor vollständig sichtbar?
function GetCurrentMonitor(Form:TForm):Integer;
var Rect : TRect; i,A,maxA : Integer; begin Result:=0; maxA :=0; for i:=0 to Screen.MonitorCount-1 do if IntersectRect(Rect,Screen.Monitors[i].BoundsRect,Form.BoundsRect) then begin A:=(Rect.Right-Rect.Left)*(Rect.Bottom-Rect.Top); if A>maxA then begin maxA :=A; Result:=i; end end end; Die Funktion prüft, ob das übergebene Form aktuell vollständig angezeigt wird.
Delphi-Quellcode:
3 - Vollständige Anzeige des Forms erzwingen
function FormFullInView(Form:TForm):Boolean;
var MonNo, MonL,MonW, MonT,MonH : Integer; begin MonNo:=GetCurrentMonitor(Form); MonL :=Screen.Monitors[MonNo].Left; MonW :=Screen.Monitors[MonNo].Width; MonT :=Screen.Monitors[MonNo].Top; MonH :=Screen.Monitors[MonNo].Height; Result:=(Form.Left >=MonL) and (Form.Top >=MonT) and (Form.Left+Form.Width <=MonL+MonW) and (Form.Top +Form.Height<=MonT+MonH) end; Die Prozedur erzwingt die vollständige Anzeige (zentriert) des Forms auf dem Monitor der mit dem Formular die größte Schnittfläche besitzt. Hat das Form in der aktuellen Konfiguration mit keinem vorhandenen Monitor eine Schnittfläche, wird der primäre Monitor verwendet. Der Aufruf kann (natürlich) erst erfolgen, nachdem Left, Top, Width und Height des Forms festgelegt wurden.
Delphi-Quellcode:
Nach Setzen der in der INI-Datei gespeicherten letzten Fensterkoordinaten wird die zuletzt gezeigte Prozedur aufgerufen. Damit wird dann sichergestellt, dass das Form unter jeder Monitorkonfiguration immer vollständig angezeigt wird - hoffe ich jedenfalls :mrgreen:
procedure FitFormFullInView(Form:TForm);
var MonNo, MonL,MonW, MonT,MonH : Integer; begin if not(FormFullInView(Form)) then begin MonNo:=GetCurrentMonitor(Form); MonL :=Screen.Monitors[MonNo].Left; MonW :=Screen.Monitors[MonNo].Width; MonT :=Screen.Monitors[MonNo].Top; MonH :=Screen.Monitors[MonNo].Height; with Form do begin Left:=MonL+(MonW-Width ) div 2; Top :=MonT+(MonH-Height) div 2; end end end; Warum poste ich das Ganze nun? Ich würde das gern noch mal von einer weiteren Person testen lassen. Vielleicht gibt es sogar in der DP-Gemeinde ein Mitglied mit 3, 4 oder noch mehr Monitoren. // edit : Rechtschreibfehler beseitigt |
Re: Vollständige Sichtbarkeit eines Forms
Oh das werde ich gleich morgen früh mal ausprobieren, ich hab nämlich gerade das Phänomen dass meine App mit XP-Manifest zwar im Modus "maximiert" auf dem Bildschirm erscheint, aber trotzdem deutlich kleiner als der Bildschirm ist. Erst zweimaliges Klicken aufs Border Icon maximiert die Applikation dann korrekt (grummel!) - ohne XP-Manifest klappts. Mal sehen ob Dein Ansatz da Abhilfe schafft :)
[edit=Phoenix]Text wiedergeholt.. Mfg, Phoenix[/edit] |
Re: Vollständige Sichtbarkeit eines Forms
Moin, Moin.
Gibt's hier im Forum kein Mitglied, das mehr als zwei Monitore hat und das mal testen kann? |
Re: Vollständige Sichtbarkeit eines Forms
Also ich hab leider keinen 2. Monitor, aber ich hab deine Funktionen im Kopf überprüft und würde sagen: Daumen hoch, sieht sehr gut aus.
GetCurrentMonitor ist piffig gelöst. Vielleicht statt TForm die Klasse TCustomForm verwenden. FitFormFullInView könnte man vielleicht besser lösen. Sobald ein Form die Monitorfläche um ein Pixel verlässt, wird es in x- und y-Richtung zentriert. Es würde aber reichen, das Form nur soweit zu verschieben, bis es nirgends mehr übersteht. Also 1.) GetCurrentMonitor aufrufen 2.) ermitteln, um wieviele Pixel das Form in x- und/oder y-Richtung übersteht 3.) Form um genau diese x/y-Beträge so verschieben, dass es vollständig im Monitor ist. Ich würde dazu nicht FormFullInView aufrufen, sondern gleich in die Rechnung einsteigen. |
Re: Vollständige Sichtbarkeit eines Forms
Vielen Dank für den Check :hi:
- TCustomForm werde ich ändern, - den zweiten Punkt erst einmal mal in der Praxis austesten. Hatte das Zentrieren gewählt, damit besonders deutlich wird, dass das Form vom Programm abweichend von der letzten Position neu positioniert wurde |
Re: Vollständige Sichtbarkeit eines Forms
Hi taaktaak,
Zitat:
Ich habe es eben mit 2 Monitoren in unterschiedlicher Anordnung getestet (1,2 / 2,1). Ich sehe auf Anhieb zwei Probleme: 1) Du berücksichtigest bei einem Resize nicht die Höhe der Taskbar und auf welchem der Monitore diese ist. WorkareaRect wäre hier der richtige Ansatz. 2) Was ist, wenn ein Benutzer wirklich das Form über mehrere Monitore vergrößern will? Es gibt ja auch Multimonitorsysteme ohne Displayrahmen, die zusammen einen großen Desktop ergeben. Dabei würde Deine Lösung immer auf einen einzelnen Monitor verkleinern. Zitat:
Ich habe gerade genau das gleiche Problem und sitze in Griffweite eines Multimonitorsystems... Ist das für Dich noch aktuell? Gruß Assertor |
Re: Vollständige Sichtbarkeit eines Forms
So,
hier mal ein Lösungsansatz für die angesprochenen Probleme: Damit erledigt FitFormFullInView zusammen mit seinen Hilfsfunktionen die folgenden Aufgaben (für Einzel- oder Multi-Monitor):
Delphi-Quellcode:
Im Ergebnis finde ich die Zentrierung auch besser.
function GetCurrentMonitor(AForm: TCustomForm): Integer;
var Rect: TRect; i, A, maxA: Integer; begin { man kann sich diese Funktion auch sparen und einfach AForm.Monitor aufrufen, wobei diese u.U. nicht so gründlich und schön auf die Maximalnutzung prüft } Result := 0; maxA := 0; for i := 0 to Screen.MonitorCount-1 do if IntersectRect(Rect, Screen.Monitors[i].BoundsRect, AForm.BoundsRect) then begin A := (Rect.Right-Rect.Left) * (Rect.Bottom-Rect.Top); if A > maxA then begin maxA := A; Result:=i; end; end; end; function FormFullInView(AForm: TCustomForm): Boolean; var MonNo, MonL, MonW, MonT, MonH: Integer; begin MonNo := GetCurrentMonitor(AForm); MonL := Screen.Monitors[MonNo].WorkareaRect.Left; MonW := Screen.Monitors[MonNo].WorkareaRect.Right - Screen.Monitors[MonNo].WorkareaRect.Left; MonT := Screen.Monitors[MonNo].WorkareaRect.Top; MonH := Screen.Monitors[MonNo].WorkareaRect.Bottom - Screen.Monitors[MonNo].WorkareaRect.Top; // handle multi-monitor windows if (AForm.Left >= Screen.DesktopLeft) and (AForm.Top >= Screen.DesktopTop) and ((AForm.Left + AForm.Width) <= (Screen.DesktopWidth + Screen.DesktopLeft)) and ((AForm.Top + AForm.Height) <= (Screen.DesktopHeight + Screen.DesktopTop)) then Result := True else Result:= (AForm.Left >= MonL) and (AForm.Top >= MonT) and (AForm.Left + AForm.Width <= MonL + MonW) and (AForm.Top + AForm.Height <= MonT + MonH); end; procedure FitFormFullInView(AForm: TCustomForm); var MonNo, MonL, MonW, MonT, MonH: Integer; begin if not (FormFullInView(AForm)) then begin MonNo := GetCurrentMonitor(AForm); MonL := Screen.Monitors[MonNo].WorkareaRect.Left; MonW := Screen.Monitors[MonNo].WorkareaRect.Right - Screen.Monitors[MonNo].WorkareaRect.Left; MonT := Screen.Monitors[MonNo].WorkareaRect.Top; MonH := Screen.Monitors[MonNo].WorkareaRect.Bottom - Screen.Monitors[MonNo].WorkareaRect.Top; with AForm do begin if Height > MonH then Height := MonH; if Width > MonW then Width := MonW; Left := MonL + (MonW-Width) div 2; Top := MonT + (MonH-Height) div 2; end; end; end; Nützlich ist die Funktion, wenn z.B. 1) ein Anwender seinen Monitor / seine Grafikkarte durch ein Modell mit anderer Standard-Auflösung ersetzt und ein Programm dann mit diesen neuen Einstellungen klar kommen muß oder 2) eine Anwendung mit Einstellungen für einen Multimonitor-PC z.B. auf einem USB-Stick mobil am Notebook eingesetzt wird. Gruß Assertor |
Re: Vollständige Sichtbarkeit eines Forms
Hi,
beim From die "Position" auf "poScreenCenter" stellen. Dann wirds auch sauber ausgerichtet. Gruss |
Re: Vollständige Sichtbarkeit eines Forms
Hi,
Zitat:
Warum also der Post :?: Gruß Assertor |
Re: Vollständige Sichtbarkeit eines Forms
Moin, Moin.
... weil ich sonst gar nicht mitbekommen hätte, dass Assertor meinen Code verbessert hast. Prima! Werde allerdings die Funktionalität Zitat:
|
Re: Vollständige Sichtbarkeit eines Forms
Hi taaktaak,
Zitat:
Gruß Assertor :cheers: |
Re: Vollständige Sichtbarkeit eines Forms
Von RWarnecke wurde in meinem aktuellen Projekt "rzDelphiGuide" ein Fehler entdeckt, der von der Prozedur FitFormFullInView() produziert wird. Für alle Interessierten hier die kleine aber wichtige Korrektur:
Position/Größe dürfen nicht korrigiert werden, wenn das Formular maximiert dargestellt wird. Der Anfang der Prozedur ist daher wie folgt zu ändern:
Delphi-Quellcode:
procedure FitFormFullInView(AForm: TCustomForm);
var MonNo, MonL, MonW, MonT, MonH: Integer; begin if (AForm.WindowState<>wsMaximized) and not (FormFullInView(AForm)) then begin .. .. |
Re: Vollständige Sichtbarkeit eines Forms
Hi taaktakk,
Zitat:
Vorteil: Wenn der Benutzer die Anwendung maximiert startet, kann er trotzdem zur vorherigen Größe zurückkehren. Und diese vorherige Größe ist dann per FitFormFullInView an die aktuellen Gegebenheiten der Bildschirme angepasst. Zusätzlich hatte ich noch ein paar Funktionen für das Speichern der tatsächlichen "normalen Größe" trotz maximiertem Fenster geschrieben und mit einer AutoSize garniert, so daß ein Erststart der Anwendungen zu einem Fenster von 80% Größe (bzw. bliebig) auf dem Primärmonitor führt. Bei Interesse kann ich die Codeschnipsel hier posten. Gruß Assertor |
Re: Vollständige Sichtbarkeit eines Forms
vorallem das rausbekommen wäre für mich interessant,
obwohl mir da grad ein Gedankenblitz gekommen ist - bei Beenden Form ausblenden (Hide), wiederherstellen (demaximieren :lol: ) und dann die Werte auslesen. |
Re: Vollständige Sichtbarkeit eines Forms
Hi Himitsu,
Zitat:
Hier aus meinem Nähkästchen:
Delphi-Quellcode:
Ist so aus einer meiner Units und wird so nicht kompilieren, aber die Idee sollte rüberkommen: TWindowPlacement.rcNormalPosition ist die einfachste Lösung dafür.
procedure SaveWindowState(AConfigFile: TXMLConfig;
AForm: TForm; const Section: UnicodeString; const AllowMinimize: Boolean = False; const AdjustNonClientHeight: Integer = 0); var p: TWindowPlacement; r: TRect; begin Assert(AConfigFile <> nil); Assert(AForm <> nil); with AConfigFile do begin if (AForm.WindowState <> wsMinimized) or (AllowMinimize) then begin { calculate window's normal size and position using Windows API call - the form's Width, Height, Top and Left properties will give maximized window size if form is maximized, which is not what we want here. AdjustNonClientHeight is used to support libraries like DevExpress Ribbon components which adjust the form size after loading to support drawing in glass/nonclient area under Vista. } p.length := SizeOf(TWindowPlacement); if not (GetWindowPlacement(AForm.Handle, @p)) then begin AppLog.Log(evtError, {$IFDEF UNICODE}Format{$ELSE}UnicodeFormat{$ENDIF}( SWindowPositionGetError, [SysErrorMessage(GetLastError)])); end else begin r := p.rcNormalPosition; WriteInteger(Section, 'Left', r.Left); WriteInteger(Section, 'Top', r.Top); WriteInteger(Section, 'Width', r.Right - r.Left); if AdjustNonClientHeight = 0 then WriteInteger(Section, 'Height', r.Bottom - r.Top) else WriteInteger(Section, 'Height', r.Bottom - r.Top + AdjustNonClientHeight); end; end; case AForm.WindowState of wsMinimized: if AllowMinimize then WriteString(Section, 'WindowState', 'Minimized'); wsMaximized: WriteString(Section, 'WindowState', 'Maximized'); else WriteString(Section, 'WindowState', 'Normal'); // wsNormal end; end; end; Beim Laden dann umgekehrt:
Delphi-Quellcode:
Gruß Assertor
[Pseudocode]
// try to load saved window positions (even if maximized to preserve size) if ValueExists(Section, 'Left') or ValueExists(Section, 'Top') or ValueExists(Section, 'Width') or ValueExists(Section, 'Height') then begin // all values or at least one of them x1 := ReadInteger(Section, 'Left', AForm.Left); y1 := ReadInteger(Section, 'Top', AForm.Top); x2 := ReadInteger(Section, 'Width', AForm.Width); y2 := ReadInteger(Section, 'Height', AForm.Height); // do the positions differ from current position? if (x1 <> AForm.Left) or (x2 <> AForm.Width) or (y1 <> AForm.Top) or (y2 <> AForm.Height) then begin AForm.SetBounds(x1, y1, x2, y2); end; end else begin // center form (with default size e.g. 80%) if values are not found CenterFormToMonitor(AForm); end; // always check if the current form fits into monitor/desktop area FitFormFullInView(AForm); // load window state // Setzte AForm.WindowState auf wsMaximized, wsNormal // (oder wsMinimized wenn wir das erlauben wollen) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:57 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