Autor Téma: Pozice okna [Posuv vždy jiný]  (Přečteno 186 krát)

Offline msamek

  • Nováček
  • *
  • Příspěvků: 2
  • Karma: 0
    • Verze Delphi: XE 10.1
Pozice okna [Posuv vždy jiný]
« kdy: 13-08-2018, 07:51:08 »
Zdravím,

řešíme problém pro ukládání / načítání pozice formulářů na obrazovce a nenapadá mě proč by to mělo dělat. V registrech jsou rozměry a pozice nastaveny správně, ale po nastavení rozměrů a pozice dochází k posunutí.

Klasický postup je :
1.) Při form destroy a form close ukládání aktuální pozice okna do registru Left, Top, Width, Height, State. (některé formuláře jsou vytvořený celou dobu běhu programu, některé se ničí při zavření.. proto ukládání v obou událostech

Kód: Delphi [Vybrat]
  1. destructor TSaveForm.Destroy;
  2. begin
  3.   SaveState;
  4.   inherited Destroy;
  5. end;
  6.  

2.) Při následné akci form nejprve ve formshow kontrolujeme registry a nastavujeme pozici okna dle registru (hodnoty v registrech jsou správně)
Po nastavení

Kód: Delphi [Vybrat]
  1. procedure TSaveForm.FormShow(Sender: TObject);
  2. begin
  3.  if (FForm.Owner <> nil) then Exit;
  4.  
  5.   LoadState;
  6.  
  7.   if Assigned(FFormShowEvent) then
  8.     FFormShowEvent(Sender);
  9. end;

3. U většiny strojů kde jsme na tento problém narazily jsme problém vyřešily pomocí WindowPlacementu
  //Windows si taky uklada pozici okna, prepisu mu ji
Kód: Delphi [Vybrat]
  1.   WindowPlacement.length := SizeOf(WindowPlacement);
  2.   Win32Check(GetWindowPlacement(FForm.Handle, WindowPlacement));
  3.   WindowPlacement.ptMinPosition := Point(ScreenMinX, ScreenMinY);
  4.   WindowPlacement.ptMaxPosition := Point(ScreenMaxX, ScreenMaxY);
  5.   WindowPlacement.rcNormalPosition.Left := FForm.Left;
  6.   WindowPlacement.rcNormalPosition.Top := FForm.Top;
  7.   WindowPlacement.rcNormalPosition.Height := FForm.Height;
  8.   WindowPlacement.rcNormalPosition.Width := FForm.Width;
  9.  
  10.   SetWindowPlacement(FForm.Handle, WindowPlacement);


A problém je v tom, že se stále najdou stroje kde po načtení je pozice okna špatně.

Nesetkal jste se někdo s tímto problémem?  Posouvá se to vertikálně po monitoru (nikoliv horizontálně v tu dobu je to správně)

Offline Ondřej Pokorný

  • Guru
  • *****
  • Příspěvků: 778
  • Karma: 56
    • Verze Delphi: Primárně Lazarus, jinak D7 až aktuální
    • Kluug.net
Re:Pozice okna [Posuv vždy jiný]
« Odpověď #1 kdy: 13-08-2018, 11:37:29 »
Musíte pořádně číst dokumentaci: https://msdn.microsoft.com/en-us/library/windows/desktop/ms632611(v=vs.85).aspx

Konkrétně:

Citace
Remarks
If the window is a top-level window that does not have the WS_EX_TOOLWINDOW window style, then the coordinates represented by the following members are in workspace coordinates: ptMinPosition, ptMaxPosition, and rcNormalPosition. Otherwise, these members are in screen coordinates.

Workspace coordinates differ from screen coordinates in that they take the locations and sizes of application toolbars (including the taskbar) into account. Workspace coordinate (0,0) is the upper-left corner of the workspace area, the area of the screen not being used by application toolbars.

The coordinates used in a WINDOWPLACEMENT structure should be used only by the GetWindowPlacement and SetWindowPlacement functions. Passing workspace coordinates to functions which expect screen coordinates (such as SetWindowPos) will result in the window appearing in the wrong location. For example, if the taskbar is at the top of the screen, saving window coordinates using GetWindowPlacement and restoring them using SetWindowPos causes the window to appear to "creep" up the screen.

To znamená, že zapomínáte na pozici Windows lišty. Typicky se to projevuje, že si dá někdo lištu nahoru a přesně o výšku lišty se posune okno dolů - to odpovídá tvému popisu "Posouvá se to vertikálně po monitoru (nikoliv horizontálně v tu dobu je to správně)". Když si šoupnete lištu doleva, tak se bude okno posouvat horizontálně.

Řešení: posunout Left/Top formuláře:

Kód: Delphi [Vybrat]
  1. MyMonitor := Screen.MonitorFromWindow(FForm.Handle);
  2. OffsetRect(FFormRect, MyMonitor.WorkareaRect.Left-MyMonitor.Left, MyMonitor.WorkareaRect.Top-MyMonitor.Top);

Já to řeším při ukládání do INI:

Kód: Delphi [Vybrat]
  1.   TCustomFormHelper = class helper for TCustomForm
  2.   public
  3.     function GetNormalPosition: TRect;
  4.   end;
  5.  
  6. function TCustomFormHelper.GetNormalPosition: TRect;
  7. var
  8.   xWP: TWindowPlacement;
  9.   xParent: HWND;
  10.   xMonitor: TMonitor;
  11. begin
  12.   xWP.length := SizeOf(xWP);
  13.   GetWindowPlacement(Handle, @xWP);
  14.   Result := xWP.rcNormalPosition;
  15.   xParent := GetAncestor(Handle, GA_PARENT);
  16.   if ((xParent=0) or (xParent=GetDesktopWindow))
  17.   and (GetWindowLong(Handle, GWL_EXSTYLE) and WS_EX_TOOLWINDOW = 0) then
  18.   begin
  19.     xMonitor := Screen.MonitorFromRect(Result);
  20.     if xMonitor<>nil then
  21.       OffsetRect(Result, xMonitor.WorkareaRect.Left-xMonitor.Left, xMonitor.WorkareaRect.Top-xMonitor.Top);
  22.   end;
  23. end;
« Poslední změna: 13-08-2018, 11:50:55 od Ondřej Pokorný »
Embarcadero Technology Partner, juj. Člen Lazarus týmu, oj.

Offline msamek

  • Nováček
  • *
  • Příspěvků: 2
  • Karma: 0
    • Verze Delphi: XE 10.1
Re:Pozice okna [Posuv vždy jiný]
« Odpověď #2 kdy: 13-08-2018, 12:17:12 »
Ano máš pravdu v tom, že nebylo řešeno pokud lištu nahoře mohl nastat problém.

Nicméně problém s pozicí okna není na každém PC, ale jen u někoho a není to závislé na pozici lišty.

Problém je vlastně vtom, že ani nevíme jestli to dělá i více lidem protože 99% lidem to že se okno při následujícím spuštění posune o pár pixelů nevadí.

Mě ani kolegům v práci to nedělá a hledat problém slepě není úplně ideální a v tomto ohledu s tímto konkrétním zákazníkem není úplně řeč.

Každopádně děkuji za radu, zkusím to a uvidí se jestli to někam vede

 

S rychlou odpovědí můžete používat BB kódy a emotikony jako v běžném okně pro odpověď, ale daleko rychleji.

Jméno: E-mail:
Ověření:
Křestní jméno zpěváka Gotta: