Title: How to Move Controls and Save their Positions
Question: The aim of this tutorial is to show, how you can allow the user to move any control, with the minimum of coding on your part. It also shows how to save these new positions to registry so that next time the application is started all the controls will appear in the position they where left in last time.
Answer:
How to Move Controls and Save their Positions
The aim of this tutorial is to show, how you can allow the user to move any control, with the minimum of coding on your part. It also shows how to save these new positions to registry so that next time the application is started all the controls will appear in the position they where left in last time.
There are only 3 short procedures in the unit, these are :
FormCreate
This loops through all the components owned by the form, if the component is a TControl then it looks in the registry for its left and top property and if its not there then it places it where ever it was placed at design time. Also it changes the cursor for each control to a cross to indicate to the user that its movable. Finally we need to assign a new application message handler so that when we get a mouse down we can perform the actual component moving.
AppMessage
This is the application message handler that we referenced earlier. This procedure is called every time our application receives a windows message, but only does anything on the Left Mouse Button Down message (wm_LBUTTONDOWN). When this message is received it releases the mouse capture, and sends a message to the control under the mouse to move mode. Finally it sets the handled var to true to indicate that it has dealt with the message.
FormDestroy
All the formDestroy does is save all the controls position to the registry by looping through all the components on the form (like in the formCreate) and saving their left and top properties.
The Code
Create a new application and drop as many controls as you want onto the main form. (I used a Tbutton, a Tedit, aTListBox and a TComboBox) You may call your controls anything you like as when their positions are saved to the registry the actual name you choose is used by using the name property of each control. Use the Object Inspector to produce stubs for the Create and Destroy events of the main form and modify your code with that shown below:
unit Main;
interface
uses
Windows,WinProcs, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Menus, registry;
type
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
ListBox1: TListBox;
ComboBox1: TComboBox;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
procedure AppMessage(var Msg: TMsg; var Handled: Boolean);
public
{ Public declarations }
end;
const
SC_SIZE = $F012;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
var
iTemp: Integer;
r : TRegIniFile;
begin
(* Open the key in the registry where we store all the positions *)
r := TRegIniFile.Create('Resize Test');
(* Loop through all the components on a form *)
for iTemp := 0 to ComponentCount -1 do
(* Get the position of all controls *)
if Components[iTemp] is TControl then
with Components[iTemp] as TControl Do
begin
left:=r.readinteger(Name,'Left',left);
top:=r.readinteger(Name,'Top',Top);
(* Make there cursors crosses *)
cursor:=crCross;
end;
(* Release the registry object *)
r.free;
(* Use our own message handler for all message sent to the application *)
Application.OnMessage := AppMessage;
end;
procedure TForm1.AppMessage(var Msg: TMsg; var Handled: Boolean);
begin
(* Only do anything if the left mouse button is pressed *)
if msg.message = wm_LBUTTONDOWN then
begin
(* Release the mouse capture *)
WinProcs.ReleaseCapture;
(* Send a message to the control under the mouse to go into move mode *)
postmessage ( msg.hwnd,WM_SysCommand, SC_SIZE, 0 );
(* Say we have handled this message *)
Handled:=true;
end;
end;
procedure TForm1.FormDestroy(Sender: TObject);
var
iTemp: Integer;
r : TRegIniFile;
begin
(* As in the form create loop through all the components But this *)
(* time write the left and top properties to the registry *)
r := TRegIniFile.Create('Resize Test');
for iTemp := 0 to ComponentCount -1 do
if Components[iTemp] is TControl then
with Components[iTemp] as TControl Do
begin
r.writeinteger(Name,'Left',left);
r.writeinteger(Name,'Top',Top);
end;
r.free;
end;
end.
The following code can be modified easily to have a design mode and a running mode by adding a flag indicating whether the
Application.OnMessage := AppMessage is needed e.g.
If fDesigning then
Application.OnMessage := AppMessage
else
Application.OnMessage := nil;
If you only want a few controls to be movable just make those controls respond to the onMousedown event.
Well I hope this is enough to get you started, and if you want furthur information including how to resize controls then have a look at the article A Cool and Easy Method for Resizing and Moving Controls at Run Time by Brent Eagles