Sign in Join
Wiki copytemporary

Remember form position and size: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11# Using TForm.SessionProperties and TXMLPropStorage
22
33In some applications, it is nice if the user modified settings for the position and size of the form are saved at program end and reused the next time the program starts. Lazarus has a fairly easy way to do this using [[TXMLPropStorage]] or [[TINIPropStorage]] available.
44
55A simple example will illustrate these functions:
66
77- create new application (main menu Project -\> New Project -\> Application)
88- pass an TXMLPropStorage component on the form (find it on the Misc tab of the component palette)
99
10-<figure>
11-<img src="KomponentenpaletteTXMLPropStorage.png" title="KomponentenpaletteTXMLPropStorage.png" />
12-<figcaption>KomponentenpaletteTXMLPropStorage.png</figcaption>
13-</figure>
10+![](/wiki-images/0/00/KomponentenpaletteTXMLPropStorage.png)
1411
1512- in the Object Inspector: XMLPropStorage1 -\> FileName eg set "session.xml"
1613- in the Object Inspector: Form1 -\> Edit sessionProperties (the \[...\] button simply click)
1714- now select each of the Form1 properties Left, Top, Width, Height and add it
1815- confirm with OK and restart project
1916- change and move the form size
2017- end the program and restart it and it will return to the size and position it ended with last time.
2118
2219Further information under [[TXMLPropStorage]]
2320
2421# General method
2522
2623## Simple example
2724
2825A basic approach to keep form position and size between application restart is to store these state values to some persistent storage like XML file, INI file or Windows registry. You need at least store TForm properties Left, Top, Width and Height. But if form is maximized state you need also store values of TForm RestoredLeft, RestoredTop, RestoredWidth and RestoredHeight so form will be correctly sized if user click on maximize botton again to switch back to normal state.
2926
3027For simplification TXMLConfig component is used as persistent storage. Place this component on your form and set its filename property to Config.xml.
3128
3229``` pascal
3330procedure TForm1.StoreFormState;
3431begin
3532 with XMLConfig1 do begin
3633 SetValue('NormalLeft', Left);
3734 SetValue('NormalTop', Top);
3835 SetValue('NormalWidth', Width);
3936 SetValue('NormalHeight', Height);
4037
4138 SetValue('RestoredLeft', RestoredLeft);
4239 SetValue('RestoredTop', RestoredTop);
4340 SetValue('RestoredWidth', RestoredWidth);
4441 SetValue('RestoredHeight', RestoredHeight);
4542
4643 SetValue('WindowState', Integer(WindowState));
4744 end;
4845end;
4946```
5047
5148Restoration of stored form properties is a little bit complicated as properties have to be set in right order to prevent form resize animation or values to be overwritten by internal form mechanism. There is a rule that if normal and restored bounds are equal then form was in normal state. If normal and restored bounds are different then form is probably in maximized state and restored bounds are set to original position and size before maximization. As we have stored WindowState then we can use it to decide if form is in maximized state. To restore maximized state we have to first set form to normal state then set TForm.BoundsRect and after that set wsMaximized state. This is because Restored properties are read only and we can set them directly.
5249
5350``` pascal
5451procedure TForm1.RestoreFormState;
5552var
5653 LastWindowState: TWindowState;
5754begin
5855 with XMLConfig1 do begin
5956 LastWindowState := TWindowState(GetValue('WindowState', Integer(WindowState)));
6057
6158 if LastWindowState = wsMaximized then begin
6259 WindowState := wsNormal;
6360 BoundsRect := Bounds(
6461 GetValue('RestoredLeft', RestoredLeft),
6562 GetValue('RestoredTop', RestoredTop),
6663 GetValue('RestoredWidth', RestoredWidth),
6764 GetValue('RestoredHeight', RestoredHeight));
6865 WindowState := wsMaximized;
6966 end else begin
7067 WindowState := wsNormal;
7168 BoundsRect := Bounds(
7269 GetValue('NormalLeft', Left),
7370 GetValue('NormalTop', Top),
7471 GetValue('NormalWidth', Width),
7572 GetValue('NormalHeight', Height));
7673 end;
7774 end;
7875end;
7976```
8077
8178Functions should be executed from OnShow and OnClose handlers.
8279
8380``` pascal
8481procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
8582begin
8683 StoreFormState;
8784end;
8885
8986procedure TForm1.FormShow(Sender: TObject);
9087begin
9188 RestoreFormState;
9289end;
9390```
9491
9592## Support for more forms
9693
9794To support storing state for multiple forms we need to extend our functions to support Form parameter and allow store their values to different XMLConfig paths.
9895
9996``` pascal
10097procedure TForm1.StoreFormState(Form: TForm);
10198begin
10299 with XMLConfig1 do begin
103100 SetValue('Forms/' + Form.Name + '/NormalLeft', Form.Left);
104101 SetValue('Forms/' + Form.Name + '/NormalTop', Form.Top);
105102 SetValue('Forms/' + Form.Name + '/NormalWidth', Form.Width);
106103 SetValue('Forms/' + Form.Name + '/NormalHeight', Form.Height);
107104
108105 SetValue('Forms/' + Form.Name + '/RestoredLeft', Form.RestoredLeft);
109106 SetValue('Forms/' + Form.Name + '/RestoredTop', Form.RestoredTop);
110107 SetValue('Forms/' + Form.Name + '/RestoredWidth', Form.RestoredWidth);
111108 SetValue('Forms/' + Form.Name + '/RestoredHeight', Form.RestoredHeight);
112109
113110 SetValue('Forms/' + Form.Name + '/WindowState', Integer(Form.WindowState));
114111 end;
115112end;
116113
117114procedure TForm1.RestoreFormState(Form: TForm);
118115var
119116 LastWindowState: TWindowState;
120117begin
121118 with XMLConfig1 do begin
122119 LastWindowState := TWindowState(GetValue('Forms/' + Form.Name + '/WindowState', Integer(Form.WindowState)));
123120
124121 if LastWindowState = wsMaximized then begin
125122 Form.WindowState := wsNormal;
126123 Form.BoundsRect := Bounds(
127124 GetValue('Forms/' + Form.Name + '/RestoredLeft', Form.RestoredLeft),
128125 GetValue('Forms/' + Form.Name + '/RestoredTop', Form.RestoredTop),
129126 GetValue('Forms/' + Form.Name + '/RestoredWidth', Form.RestoredWidth),
130127 GetValue('Forms/' + Form.Name + '/RestoredHeight', Form.RestoredHeight));
131128 Form.WindowState := wsMaximized;
132129 end else begin
133130 Form.WindowState := wsNormal;
134131 Form.BoundsRect := Bounds(
135132 GetValue('Forms/' + Form.Name + '/NormalLeft', Form.Left),
136133 GetValue('Forms/' + Form.Name + '/NormalTop', Form.Top),
137134 GetValue('Forms/' + Form.Name + '/NormalWidth', Form.Width),
138135 GetValue('Forms/' + Form.Name + '/NormalHeight', Form.Height));
139136 end;
140137 end;
141138end;
142139
143140procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
144141begin
145142 StoreFormState(Self);
146143end;
147144
148145procedure TForm1.FormShow(Sender: TObject);
149146begin
150147 RestoreFormState(Self);
151148end;
152149```
153150
154151## Minimized and Fullscreen states
155152
156153TForm.WindowState have two additional states wsMinimized and wsFullscreen. These special states need special care if they should be supported.
157154
158155## Ensure that restored form is visible
159156
160157As size of screen can change in time we need to check restored form position and size to ensure that form is visible to user and so your can manipulate with them.
161158
162159``` pascal
163160function TForm1.CheckFormIsEntireVisible(Rect: TRect): TRect;
164161var
165162 Width: Integer;
166163 Height: Integer;
167164begin
168165 Result := Rect;
169166 Width := Rect.Right - Rect.Left;
170167 Height := Rect.Bottom - Rect.Top;
171168 if Result.Left < (Screen.DesktopLeft) then begin
172169 Result.Left := Screen.DesktopLeft;
173170 Result.Right := Screen.DesktopLeft + Width;
174171 end;
175172 if Result.Right > (Screen.DesktopLeft + Screen.DesktopWidth) then begin
176173 Result.Left := Screen.DesktopLeft + Screen.DesktopWidth - Width;
177174 Result.Right := Screen.DesktopLeft + Screen.DesktopWidth;
178175 end;
179176 if Result.Top < Screen.DesktopTop then begin
180177 Result.Top := Screen.DesktopTop;
181178 Result.Bottom := Screen.DesktopTop + Height;
182179 end;
183180 if Result.Bottom > (Screen.DesktopTop + Screen.DesktopHeight) then begin
184181 Result.Top := Screen.DesktopTop + Screen.DesktopHeight - Height;
185182 Result.Bottom := Screen.DesktopTop + Screen.DesktopHeight;
186183 end;
187184end;
188185```
189186
190187If requirement for entire form surface to be visible is too strong then we could check that at least part of form is visible. Here Part is size in pixels which should be at least visible for both horizontal and vertical position and size.
191188
192189``` pascal
193190function TForm1.CheckFormIsPartialVisible(Rect: TRect; Part: Integer): TRect;
194191var
195192 Width: Integer;
196193 Height: Integer;
197194begin
198195 Result := Rect;
199196 Width := Rect.Right - Rect.Left;
200197 Height := Rect.Bottom - Rect.Top;
201198 if Result.Right < (Screen.DesktopLeft + Part) then begin
202199 Result.Left := Screen.DesktopLeft + Part - Width;
203200 Result.Right := Screen.DesktopLeft + Part;
204201 end;
205202 if Result.Left > (Screen.DesktopLeft + Screen.DesktopWidth - Part) then begin
206203 Result.Left := Screen.DesktopLeft + Screen.DesktopWidth - Part;
207204 Result.Right := Screen.DesktopLeft + Screen.DesktopWidth - Part + Width;
208205 end;
209206 if Result.Bottom < (Screen.DesktopTop + Part) then begin
210207 Result.Top := Screen.DesktopTop + Part - Height;
211208 Result.Bottom := Screen.DesktopTop + Part;
212209 end;
213210 if Result.Top > (Screen.DesktopTop + Screen.DesktopHeight - Part) then begin
214211 Result.Top := Screen.DesktopTop + Screen.DesktopHeight - Part;
215212 Result.Bottom := Screen.DesktopTop + Screen.DesktopHeight - Part + Height;
216213 end;
217214end;
218215```
219216
220217# See also
221218
222219- [[Form Tutorial]]
223220
224221---
225222*From the Free Pascal wiki, page "Remember form position and size", as it stood on 2020-02-25 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
226223Category: Lazarus
227224Category: Tutorials

Back to history