Delphi-PRAXiS
Seite 1 von 3  1 23      

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 Fensterposition zurücksetzen (https://www.delphipraxis.net/203461-fensterposition-zuruecksetzen.html)

haentschman 19. Feb 2020 09:07

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:

KodeZwerg 19. Feb 2020 09:13

AW: Fensterposition zurücksetzen
 
MakeFullyVisible
MakeFullyVisible

So etwas eventuell? Keine Ahnung ob es das jetzt noch gibt?

Uwe Raabe 19. Feb 2020 09:17

AW: Fensterposition zurücksetzen
 
Gibt es: Vcl.Forms.TCustomForm.MakeFullyVisible

haentschman 19. Feb 2020 10:08

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;

uligerhardt 19. Feb 2020 10:23

AW: Fensterposition zurücksetzen
 
Du könntest auch MSDN-Library durchsuchenSetWindowPlacement & Co. verwenden. Das sorgt automatisch dafür, dass das Fenster nicht komplett verschwindet.

TigerLilly 21. Feb 2020 09:01

AW: Fensterposition zurücksetzen
 
Gibt es MakeFullyVisible nur für die VCL? Nicht FMX?

Uwe Raabe 21. Feb 2020 09:56

AW: Fensterposition zurücksetzen
 
Das ist leider so.

TigerLilly 21. Feb 2020 10:19

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.

himitsu 21. Feb 2020 10:54

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:
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;
Für RectWidth/RectHeight gibt es inzwischen einen ClassHelper mit Property Width/Height.

Dann noch paar Optimierungen, wie z.B. die Größe/Position nicht schrittweise anzupassen, sondern das nur einmal zuzuweisen.
Delphi-Quellcode:
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;
Nun noch paar "persönliche" Sonderfälle rein, die MakeFullyVisible natürlich nicht wissen kann.
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;

DieDolly 22. Feb 2020 10:02

AW: Fensterposition zurücksetzen
 
Zitat:

Gibt es MakeFullyVisible nur für die VCL? Nicht FMX?
Wenn das Fenster nicht sichtbar ist, setzt man es einfach auf den ersten Monitor. Dafür braucht man keine großartigen Funktionen mit tollen Namen, die es nur für VCL aber nicht FMX gibt.

Delphi-Quellcode:
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;
Und falls es MonitorFromWindow für FMX nicht gibt, dann haben die FMX-Leute eben Pech gehabt ;)


Alle Zeitangaben in WEZ +1. Es ist jetzt 03:49 Uhr.
Seite 1 von 3  1 23      

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