![]() |
Fensterposition zurücksetzen
Hallöle...:P
Nur aus Interesse. Unsere Anwendung speichert die Positionen der einzelnen Fenster. Soweit so gut. :wink: Geht der Mitarbeiter an einen anderen Platz, wo die Monitore vertauscht sind, ist ggf. das Fenster nicht sichtbar. (Position außerhalb des Desktops) Ich habe mir selbst eine simple Logik dafür implementiert. Die Frage ist, gibt es was vom System, um das Fenster in den sichtbaren Bereich zu bringen? :wink: Diskussion eröffnet... :wink: |
AW: Fensterposition zurücksetzen
|
AW: Fensterposition zurücksetzen
|
AW: Fensterposition zurücksetzen
Danke... :P
Man lernt nicht aus. Ich habe meine Logic ausgetauscht. :thumb:
Delphi-Quellcode:
procedure TfoBase.RestoreForm(Name: string);
var Desktop: TRect; begin FIniPath := FFolders.Items[ftPositionFolder] + Name; // wiederverwendbar für Save prsBase.StorageName := FIniPath; prsBase.RestoreFrom; // wieder einblenden if Self.WindowState = wsMinimized then begin Self.WindowState := wsNormal; end; // Prüfung ob im Desktop Desktop := Screen.DesktopRect; if Self.Left < Desktop.Left then begin Self.MakeFullyVisible(Screen.Monitors[0]); end; if Self.Left > Desktop.Width then begin Self.MakeFullyVisible(Screen.Monitors[Screen.MonitorCount - 1]); end; SaveForm; end; |
AW: Fensterposition zurücksetzen
Du könntest auch
![]() |
AW: Fensterposition zurücksetzen
Gibt es MakeFullyVisible nur für die VCL? Nicht FMX?
|
AW: Fensterposition zurücksetzen
Das ist leider so.
|
AW: Fensterposition zurücksetzen
Ja, ich hab grad im Source nachgesehen. Für FMX ist das wohl aufwändiger, weil die plattformspezifischen Dienste ins Spiel kommen.
|
AW: Fensterposition zurücksetzen
Hatte das vorher nicht gekannt und mir sowas selbst gebaut.
Ist jetzt kein Hexenwerk ... einfach gucken ob Form in einem Monitor liegt und wenn nicht, dann die Werte anpassen. Und dabei lassen sich dann auch sondefälle behandeln. Ist jetzt auch VCL, aber lässt sich bestimmt leicht anpassen, wenn es dort sowas wie Screens gibt. (Vcl.Forms.Screens, Vcl.Forms.Application, usw. auf Fmx.Forms stellen) Wobei, für Android/iOS kann man es ignoeieren, wenn/da dort alle Fenster Vollbild sind und bei Anschluß eines externen Monitors der Screen nur gespiegelt wird. Und wenn nicht, dann kann man Android/iOS zumindestens fragen wie groß der "eine" Screen ist und das als WorkArea nutzen, oder einfach die Position seiner Hauptform verwenden, die Vollbild ist und daher weiß so sie liegt. Brauchst also nur noch was für MAC und Linux kannst'e mit FMX eh vergessen. WorkArea = das ohne Taskleiste und andere AppBars
Delphi-Quellcode:
Für RectWidth/RectHeight gibt es inzwischen einen ClassHelper mit Property Width/Height.
procedure CorrectWindowPosition(Form: TForm);
begin if Form.WindowState <> wsNormal then Exit; Monitor := Form.Monitor; if not Assigned(Monitor) then Monitor := Application.MainForm.Monitor; if Form.Width > RectWidth(Monitor.WorkareaRect) then Form.Width := RectWidth(Monitor.WorkareaRect); if Form.Height > RectHeight(Monitor.WorkareaRect) then Form.Height := RectHeight(Monitor.WorkareaRect); if Form.Left < Monitor.WorkareaRect.Left then Form.Left := Monitor.WorkareaRect.Left; if Form.Top < Monitor.WorkareaRect.Top then Form.Top := Monitor.WorkareaRect.Top; if Form.Left + Form.Width >= Monitor.WorkareaRect.Right then Form.Left := Monitor.WorkareaRect.Right - Form.Width; if Top + Form.Height >= Monitor.WorkareaRect.Bottom then Form.Top := Monitor.WorkareaRect.Bottom - Form.Height; end; Dann noch paar Optimierungen, wie z.B. die Größe/Position nicht schrittweise anzupassen, sondern das nur einmal zuzuweisen.
Delphi-Quellcode:
Nun noch paar "persönliche" Sonderfälle rein, die MakeFullyVisible natürlich nicht wissen kann.
procedure CorrectWindowPosition(Form: TForm; Monitor: TMonitor = nil);
var R: TRect; Left, Top, Width, Height: Integer; begin if Form.WindowState <> wsNormal then Exit; Left := Form.Left; Top := Form.Top; Width := Form.Width; Height := Form.Height; if not Assigned(Monitor) then begin Monitor := Screen.MonitorFromRect(Bounds(Left, Top, Width, Height)); //Monitor := Form.Monitor; aber falls Form noch nicht sichtbar war... if not Assigned(Monitor) then Monitor := Application.MainForm.Monitor; end; R := Monitor.WorkareaRect; if Width > RectWidth(R) then Width := RectWidth(R); if Height > RectHeight(R) then Height := RectHeight(R); if Left < R.Left then Left := R.Left; if Top < R.Top then Top := R.Top; if Left + Width >= R.Right then Left := R.Right - Width; if Top + Height >= R.Bottom then Top := R.Bottom - Height; if not EqualRect(Form.BoundsRect, Bounds(Left, Top, Width, Height)) then Form.BoundsRect := Bounds(Left, Top, Width, Height); end; Und hier kann es auch eine Form auf dem "ganzen" Desktop sein, bzw. die über mehrere Monitore geht.
Delphi-Quellcode:
const
ScreenOverDesktop = TMonitor(1); // Multimonitor: über gesamten Desktop ScreenOverMonitor = TMonitor(0); // über einen einzelnen Monitor procedure CorrectWindowPosition(Form: TForm; Monitor: TMonitor = ScreenOverMonitor); var R: TRect; W20, H33, FormGlassFrameWidth: Integer; Left, Top, Width, Height: Integer; begin if Form.WindowState <> wsNormal then Exit; Left := Form.Left; Top := Form.Top; Width := Form.Width; Height := Form.Height; W20 := Form.Width div 5; // darf bis zu 20% links oder rechts überstehen H33 := Form.Height div 3; // darf bis zu 33% unten überstehen {$REGION 'SETFORMPOS: Toolform ausrichten wenn Modulform verschoben wurde'} if Form.ClassNameIs('TToolForm') and (Form.Owner is TForm) then begin W20 := 0; H33 := 0; FormGlassFrameWidth := 4; if not NoNewCommonControls then // WinXP schmalere Ränder FormGlassFrameWidth := 8; if ((Form.Owner as TForm).BorderStyle in [bsToolWindow, bsSizeToolWin]) or ((TForm(Form.Owner).FormStyle = fsNormal) and (TForm(Form.Owner).BorderStyle in [bsSizeable, bsDialog])) then FormGlassFrameWidth := FormGlassFrameWidth - IfThen(NoNewCommonControls, 3, 5); if Form.Parent = Application.MainForm then begin //FormStyle=fsMDIChild Left := Max(Max(TFormAccsess(Form.Owner).GetClientOrigin.X - 34, Application.MainForm.Left - 30) - Application.MainForm.Left - FormGlassFrameWidth, 0); Top := Max( TFormAccsess(Form.Owner).GetClientOrigin.Y, Application.MainForm.Top) - Application.MainForm.Top; end else begin Left := TForm(Form.Owner).Left - 24 - FormGlassFrameWidth; Top := TForm(Form.Owner).Top + 20; end; end; {$ENDREGION} if Form.FormStyle = fsMDIChild then begin R := Application.MainForm.ClientRect; Dec(R.Bottom, RibbonHeight); // MainForm.RibbonMain.Height (Top/Left ist verschoben) Dec(R.Right, 25); // MainForm.PanelLeft.Width { TODO : alternativ alle Komponenten, mit Align <> alNone und alClient, von R abrechnen} end else if Assigned(Form.Parent) then R := Form.Parent.ClientRect else if Monitor = ScreenOverDesktop then begin // Bugfix: Fenster über mehrere Monitore http://redmine.prodat-sql.de/issues/5855 { TODO : Schwarze Bereiche, bei unterschiedlich großen oder verschobenen Monitoren, werden nicht beachtet } R := Screen.DesktopRect; end else begin //R := Screen.MonitorFromRect(Form.Monitor.BoundsRect, mdNearest).WorkareaRect; if not Assigned(Monitor) then begin Monitor := Screen.MonitorFromRect(Bounds(Left, Top, Width, Height)); //Monitor := Form.Monitor; if not Assigned(Monitor) then Monitor := Application.MainForm.Monitor; end; R := Monitor.WorkareaRect; end; {$REGION 'SETFORMPOS: Fensterposition prüfen und anpassen'} if Width > RectWidth(R) then Width := RectWidth(R); if Height > RectHeight(R) then Height := RectHeight(R); if Left + W20 < R.Left then Left := R.Left; if Top {+ H33} < R.Top then Top := R.Top; if Left + Width - W20 > R.Right then Left := R.Right - Width; if Top + Height - H33 > R.Bottom then Top := R.Bottom - Height; {$ENDREGION} if not EqualRect(Form.BoundsRect, Bounds(Left, Top, Width, Height)) then begin Form.BoundsRect := Bounds(Left, Top, Width, Height); // Form.Left/Top/Width/Height := ... ProcessDrawMessages(False); end; end; |
AW: Fensterposition zurücksetzen
Zitat:
Delphi-Quellcode:
Und falls es MonitorFromWindow für FMX nicht gibt, dann haben die FMX-Leute eben Pech gehabt ;)
if (Screen.MonitorFromWindow(AForm.Handle, mdNull) = nil) and (Screen.MonitorCount > 0) then
begin // AForm.Top := (Screen.Monitors[0].Height - AForm.Height) div 2; // AForm.Left := (Screen.Monitors[0].Width - AForm.Width) div 2; end; |
AW: Fensterposition zurücksetzen
In der VCL gibt es auch direkt TForm.Monitor für den Monitor wo die Form zum größten Teil drauf ist, (also der Monitor auf dem der Mittelpunkt der Form liegt)
aber im FMX nicht und in FMX.Forms gibt es nicht so eine Screen-Klasse, wie in VCL.Forms. Gut, man kann natürlich problemlos via den APIs in Winapi.Windows selber das mit den Monitoren machen, aber natürlich nur im Windows. |
AW: Fensterposition zurücksetzen
Liste der Anhänge anzeigen (Anzahl: 2)
Moin...:P
Meine neue Logic funktioniert nicht. :evil: Die einzelnen Monitore haben nicht die erwarteten Größen. (siehe Bilder) Kann jemand logisch erklären? Danke...:wink: |
AW: Fensterposition zurücksetzen
Die Koordinaten geben an, welchen Bereich des Desktops ein Monitor abdeckt.
|
AW: Fensterposition zurücksetzen
Hab jetzt nur in der VCL geguckt, da gibt es
![]() Und die Reihenfolge in der Liste ist einfach entsprechend dem, wie ![]() [edit] Nee, MonitorNum ist List.Count beim Einfügen, also das Gleiche. :oops: Tja, dann ist Windows böse zu dir. PS: ![]() |
AW: Fensterposition zurücksetzen
Zitat:
Das sind die Werte die im Tool zu sehen sind.
Delphi-Quellcode:
procedure TfoMonitor.FormShow(Sender: TObject);
begin grpMonitor.Caption := 'Monitornummer ' + IntToStr(Monitor.MonitorNum + 1); lbl5.Caption := IntToStr(Monitor.Left); lbl6.Caption := IntToStr(Monitor.Top); lbl7.Caption := IntToStr(Monitor.Height); lbl8.Caption := IntToStr(Monitor.Width); end; |
AW: Fensterposition zurücksetzen
PS: Hatte meine Antwort oben nochmal revidiert.
Delphi übernimmt einfach die Reihenfolge von der WinAPI und GetMonitorInfo(Monitor.Handle, ...) liefert auch keine zusätzlichen Infos. (nur Primary und die Rects) Wenn Windows das schon falsch rausgibt, dann kannst da über die TScreen-Klasse nichts weiter machen. Falls du die Reihenfolge zur Laufzeit geändert hast, dann "sollte" Delphi eigenlich drauf reagieren und die Daten neu einlesen. |
AW: Fensterposition zurücksetzen
Daß heist, daß man sich auf die Monitoranordnung, was aus dem System kommt, nicht verlassen kann. :evil: Darauf baut aber die Logik. :roll:
|
AW: Fensterposition zurücksetzen
Zumindestens nicht komplett.
Primary = 1, not Primary = >1 und die Positionen sollten ja stimmen. bist nicht der Einzige: ![]() ![]() ... > Wie Sie vielleicht wissen, listet Windows dieAnzeigegeräte in der Reihenfolge, in der Sie sie verbinden (oder in der Tat überhaupt nicht auf einer Regel basieren?). ![]() > Beachten Sie, dass sich einige Teile dieser Muster abhängig von der Installations Reihenfolge ändern können. vielleicht noch ![]() |
AW: Fensterposition zurücksetzen
Zitat:
Ich werde meine Logik anpassen. Ich werde mir die Monitore separat auslesen und die linke Seite passend setzen. :? |
AW: Fensterposition zurücksetzen
Ich hab die Lösung:
Du löst das Monitor identifizieren vom OS aus und via OCR liest du dann die Numern vom Screenshot ab. :lol: |
AW: Fensterposition zurücksetzen
Zitat:
|
AW: Fensterposition zurücksetzen
Da ich mich selber gerade ziemlich mit Unregelmäßigkeiten bei der Fensterpositionierung herumgeärgert habe, möchte ich an dieser Stelle noch anmerken, dass MakeFullyVisible nicht die Eigenheiten von Windows 10 berücksichtigt.
Windows 10 hat nämlich noch einen unsichtbaren Rand von normalerweise 7px. Siehe im Detail hier: ![]() Hat der Anwender also beispielsweise das Fenster links angedockt und man speichert diese Position beim Beenden der Anwendung mit (x=0,y=0), möchte man nach dem Programmstart die Anwendung ja auch an die gleiche Position wieder setzen, was eigentlich ja auch geht, aber führt man dann MakeFullyVisible aus, weil man sichergehen möchte, dass die Anwendung nicht irgendwo versteckt ist, weil sich die angeschlossenen Monitore geändert haben, dann wird das Fenster auf x=7,y=0 verschoben. Die einzige Option, die ich das sehe, wäre den Code von MakeFullyVisible zu kopieren und mit entsprechenden Toleranzen an den Rändern anzupassen. |
AW: Fensterposition zurücksetzen
Fensterpositionen sind in der Tat seit MS in Windows 10 die Monitor-API v2 umgesetzt hat eine komplexe Angelegenheit geworden. Das glaubt man erst, wenn man sich damit beschäftigt hat.
Für etwas Input will ich auf meine Unit ![]() ![]() Die dort enthaltenen Funktionen GetWindowRectDominaStyle und SetWindowPosDominaStyle funktionieren zumindest in meinen Testumgebungen zuverlässig. Nur falls sich jemand mit der Materie beschäftigen möchte... |
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:38 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz