Иллюстрации с сайта windows.microsoft.com |
Раньше для сохранения позиции окна приложения я часто использовал простой код:
procedure Store( F: TForm ); var wp: TWindowPlacement; begin with TIniFile.Create( ChangeFileExt( Application.ExeName, '.ini' ) ) do try wp.length := SizeOf( TWindowPlacement ); GetWindowPlacement( F.Handle, @wp ); with wp.rcNormalPosition do begin WriteInteger( F.ClassName, 'Left', Left ); WriteInteger( F.ClassName, 'Top', Top ); WriteInteger( F.ClassName, 'Width', Right - Left ); WriteInteger( F.ClassName, 'Height', Bottom - Top ); end; WriteBool(F.ClassName, 'Maximized', F.WindowState = wsMaximized ); finally Free; end; end;
Я использовал не "внешние" (Left, Top, Width, Height) координаты окна, а "нормальные", полученные ф-ей GetWindowPlacement, т.к. в случае разворачивания окна на весь экран узнать потом его нормальный размер по "внешним" координатам нельзя. Разумеется, в случае, если окно и так имеет нормальный размер, "нормальные" координаты совпадают с "внешними". Вызов всего одной ф-ии работал на все случаи жизни.
А для восстановления позиции и размеров я делал так:
procedure Restore( F: TForm ); begin with TIniFile.Create( ChangeFileExt( Application.ExeName, '.ini' ) ) do try F.Left := ReadInteger( F.ClassName, 'Left' , F.Left ); F.Top := ReadInteger( F.ClassName, 'Top' , F.Top ); F.Width := ReadInteger( F.ClassName, 'Width' , F.Width ); F.Height := ReadInteger( F.ClassName, 'Height', F.Height ); if ReadBool(F.ClassName, 'Maximized', F.WindowState = wsMaximized ) then F.WindowState := wsMaximized; finally Free; end; end;
В итоге не только восстанавливались бывшие до закрытия размеры, но и, в случае разворачивания на весь экран пересозданного окна, можно было потом свернуть его в нормальные размеры. Это было очень приятно.
Однако, в новых (конечно, всё относительно) версиях Windows появилась "привязка" окна мышью. Теперь картина стала менее радостной - для программного кода состояние "привязанного" окна TForm.WindowState остаётся прежним, "нормальные" координаты окна и флаги в структуре TWindowPlacement не меняются, и, соответственно, при перезапуске приложения его окно появляется совсем не в том виде, в каком оно было при предыдущем закрытии. Это неприятно.
Процедуру сохранения координат пришлось переписать:
Вероятно, в будущих версиях Delphi на это обстоятельство обратят внимание. Вероятно, уже сейчас в WinAPI есть методы определения этой ситуации, просто я пока не смог этого найти. Но также вероятно, что ничего этого нет и не будет. Об этом говорит хотя бы поведение окна при привязке, разворачивании и восстановлении.
Eсли вы знаете о том, как иначе определить и использовать новый вид состояния окна, напишите.
procedure Store( F: TForm ); var wp: TWindowPlacement; R: Trect; M: Boolean; begin M := F.WindowState = wsMaximized; if M then begin wp.length := SizeOf( TWindowPlacement ); GetWindowPlacement( F.Handle, @wp ); R := wp.rcNormalPosition; end else GetWindowRect( F.Handle, R );
with TIniFile.Create( ChangeFileExt( Application.ExeName, '.ini' ) ) do try with R do begin WriteInteger( F.ClassName, 'Left', Left ); WriteInteger( F.ClassName, 'Top', Top ); WriteInteger( F.ClassName, 'Width', Right - Left ); WriteInteger( F.ClassName, 'Height', Bottom - Top ); end; WriteBool(F.ClassName, 'Maximized', M ); finally Free; end; end;Т.е. теперь прежние, полученные ф-ей GetWindowPlacement "нормальные" координаты я беру только в случае, если окно "развёрнуто на весь экран". В остальных случаях я использую "внешние" координаты, полученные ф-ей GetWindowRect.
Вероятно, в будущих версиях Delphi на это обстоятельство обратят внимание. Вероятно, уже сейчас в WinAPI есть методы определения этой ситуации, просто я пока не смог этого найти. Но также вероятно, что ничего этого нет и не будет. Об этом говорит хотя бы поведение окна при привязке, разворачивании и восстановлении.
Eсли вы знаете о том, как иначе определить и использовать новый вид состояния окна, напишите.
Комментариев нет:
Отправить комментарий