1. Technology
How to Move and Resize Controls at Run Time
While in most situations you will arrange all the controls on a Delphi form in a "fixed" position, there are situations when you need to allow a user to change the placement and dimension of controls at run-time.
 More of this Feature
• Download Project Source

• Part 2
• Part 3
 Join the Discussion
"Post your views, comments, questions and doubts to this article."
Discuss!
 Related Resources
• Using Delphi components
• Owner vs. Parent
• TScreen object
• Mouse events
• Dragging and dropping

Here's how to enable dragging and resizing controls (on a Delphi form) with mouse, while the application is running.

Form editor at run-time
Once you place a control (visual component) on the form, you can adjust its position, size, and other design-time properties.
There are situations, though, when you have to allow a user of your application to reposition form controls and change their size, at run-time.

To enable runtime user movement and resizing of controls on a form with a mouse, three mouse related events need special handling: OnMouseDown, OnMouseMove and OnMouseUp.

In theory...
Let's say you want to enable a user to move (and resize) a button control, with mouse, at run-time. Firstly, you handle the OnMouseDown event to enable the user to "grab" the button. Next, the OnMouseMove event should reposition (move, drag) the button. Finally, OnMouseUp should finish the move operation.

Dragging and resizing form controls ... in practice
Firstly, drop several controls on a form. Have a CheckBox to enable or disable moving and resizing controls at run time:

Run Time Form Designer

Next, define three procedures (in the interface section of the form declaration) that will handle mouse events as described above:

type
  TForm1 = class(TForm)
  ...
  procedure ControlMouseDown(Sender: TObject; 
                             Button: TMouseButton; 
                             Shift: TShiftState; 
                             X, Y: Integer);
  procedure ControlMouseMove(Sender: TObject; 
                             Shift: TShiftState; 
                             X, Y: Integer);
  procedure ControlMouseUp(Sender: TObject; 
                           Button: TMouseButton; 
                           Shift: TShiftState; 
                           X, Y: Integer);
  private
  inReposition : boolean;
  oldPos : TPoint;                        

Note: Two form level variables are required to mark if control movement is taking place (inReposition) and to store control old position (oldPos).

In the form's OnLoad event, assign mouse event handling procedures to corresponding events (for those controls you want to be draggable/resizable):

procedure TForm1.FormCreate(Sender: TObject);
begin
  Button1.OnMouseDown := ControlMouseDown;
  Button1.OnMouseMove := ControlMouseMove;
  Button1.OnMouseUp := ControlMouseUp;

  Edit1.OnMouseDown := ControlMouseDown;
  Edit1.OnMouseMove := ControlMouseMove;
  Edit1.OnMouseUp := ControlMouseUp;

  Panel1.OnMouseDown := ControlMouseDown;
  Panel1.OnMouseMove := ControlMouseMove;
  Panel1.OnMouseUp := ControlMouseUp;

  Button2.OnMouseDown := ControlMouseDown;
  Button2.OnMouseMove := ControlMouseMove;
  Button2.OnMouseUp := ControlMouseUp;
end; (*FormCreate*)

Note: the above code enables run-time reposition of Button1, Edit1, Panel1 and Button2.

Finally, here's the magic code:

procedure TForm1.ControlMouseDown(
  Sender: TObject;
  Button: TMouseButton;
  Shift: TShiftState;
  X, Y: Integer);
begin
  if (chkPositionRunTime.Checked) AND 
     (Sender is TWinControl) then
  begin
    inReposition:=True;
    SetCapture(TWinControl(Sender).Handle);
    GetCursorPos(oldPos);
  end;
end; (*ControlMouseDown*)

ControlMouseDown in short: once a user presses a mouse button over a control, if run-time reposition is enabled (check box chkPositionRunTime is Checked) and the control that received the mouse down even is derived from TWinControl, mark that control reposition is taking place (inReposition:=True) and make sure all mouse processing is captured for the control - to prevent default "click" events from being processed.

procedure TForm1.ControlMouseMove(
  Sender: TObject;
  Shift: TShiftState;
  X, Y: Integer);
const
  minWidth = 20;
  minHeight = 20;
var
  newPos: TPoint;
  frmPoint : TPoint;
begin
  if inReposition then
  begin
    with TWinControl(Sender) do
    begin
      GetCursorPos(newPos);

      if ssShift in Shift then
      begin //resize
        Screen.Cursor := crSizeNWSE;
        frmPoint := ScreenToClient(Mouse.CursorPos);
        if frmPoint.X > minWidth then 
          Width := frmPoint.X;
        if frmPoint.Y > minHeight then 
          Height := frmPoint.Y;
      end
      else //move
      begin
        Screen.Cursor := crSize;
        Left := Left - oldPos.X + newPos.X;
        Top := Top - oldPos.Y + newPos.Y;
        oldPos := newPos;
      end;
    end;
  end;
end; (*ControlMouseMove*)

ControlMouseMove in short: change the Screen Cursor to reflect the operation: if the Shift key is pressed allow control resizing, or simply move the control to a new position (where the mouse is going). Note: minWidth and minHeight constants provide a sort of size constraint (minimum control width and height).

When the mouse button is released, dragging or resizing is over:

procedure TForm1.ControlMouseUp(
  Sender: TObject;
  Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if inReposition then
  begin
    Screen.Cursor := crDefault;
    ReleaseCapture;
    inReposition := False;
  end;
end; (*ControlMouseUp*)

ControlMouseUp in short: when a user has finished moving (or resizing the control) release the mouse capture (to enable default click processing) and mark that reposition is finished.

And that does it! Download the sample application and try for yourself.

Moving Control at RunTime

Note: Another way to move controls at run-time is to use Delphi's drag and drop related properties and methods (DragMode, OnDragDrop, DragOver, BeginDrag, etc.). Dragging and dropping can be used to let users drag items from one control - such as a list box or tree view - into another.

How to remember control position and size?
If you allow a user to move and resize form controls, you have to ensure that control placement is somehow saved when the form is closed and that each control's position is restored when the form is created / loaded. Here's how to store the Left, Top, Width and Height properties, for every control on a form, in an INI file.

How about 8 Size Handles?
When you allow a user to move and resize controls on Delphi form, at run-time using the mouse, to fully mimic the design-time environment, you should add eight size handles to the control being resized.

8 Size Handles at Run-Time

If you need any kind of help at this point, please post to the Delphi Programming Forum where all the questions are answered and beginners are treated as experts.

Next part > Add 8 sizing handles > Part 1, 2, 3

©2014 About.com. All rights reserved.