Einzelnen Beitrag anzeigen

Benutzerbild von himitsu
himitsu
Online

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.063 Beiträge
 
Delphi 12 Athens
 
#9

AW: Fensterposition zurücksetzen

  Alt 21. Feb 2020, 11:54
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;
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu (21. Feb 2020 um 12:05 Uhr)
  Mit Zitat antworten Zitat