Click here to Skip to main content
15,882,017 members
Articles / Multimedia / GDI+
Article

Drawing Resizable Controls at Runtime

Rate me:
Please Sign up or sign in to vote.
4.12/5 (15 votes)
4 Mar 2008CPOL1 min read 59.5K   6.7K   32   16
How to draw resizable controls at runtime
resizablecontrols.gif

Introduction

This article will show how to draw borders around graphical objects and place them on the form, so users can manipulate the objects by dragging them around or resizing the controls. I hope this helps someone.

Background

I am involved in a project in which one tiny aspect of the application is where end users can place various objects on the forms and manipulate their properties. The application was developed in Delphi and I was curious what it would take to do something similar in .NET.

Using the Code

First, define the size of the drag handle that will appear around the control.

C#
const int DRAG_HANDLE_SIZE = 7;

The method to actually draw the borders and the drag handles is as follows:

C#
/// <summary>
/// Draw a border and drag handles around the control, on mouse down and up.
/// </summary>
/// <param name=""sender"" ></param >
private void DrawControlBorder(object sender)
{
    Control control = (Control)sender;
    //define the border to be drawn, it will be offset by DRAG_HANDLE_SIZE / 2
    //around the control, so when the drag handles are drawn they will seem to be
    //connected in the middle.
    Rectangle Border = new Rectangle(
        new Point(control.Location.X - DRAG_HANDLE_SIZE / 2, 
            control.Location.Y - DRAG_HANDLE_SIZE / 2), 
        new Size(control.Size.Width + DRAG_HANDLE_SIZE, 
            control.Size.Height + DRAG_HANDLE_SIZE));
    //define the 8 drag handles, that has the size of DRAG_HANDLE_SIZE
    Rectangle NW = new Rectangle(
        new Point(control.Location.X - DRAG_HANDLE_SIZE, 
            control.Location.Y - DRAG_HANDLE_SIZE), 
        new Size(DRAG_HANDLE_SIZE, DRAG_HANDLE_SIZE));
    Rectangle N = new Rectangle(
        new Point(control.Location.X + control.Width / 2 - DRAG_HANDLE_SIZE/2, 
            control.Location.Y - DRAG_HANDLE_SIZE), 
        new Size(DRAG_HANDLE_SIZE, DRAG_HANDLE_SIZE));
    Rectangle NE = new Rectangle(
        new Point(control.Location.X + control.Width, 
            control.Location.Y - DRAG_HANDLE_SIZE), 
        new Size(DRAG_HANDLE_SIZE, DRAG_HANDLE_SIZE));
    Rectangle W = new Rectangle(
        new Point(control.Location.X - DRAG_HANDLE_SIZE, 
            control.Location.Y + control.Height/2-DRAG_HANDLE_SIZE/2), 
        new Size(DRAG_HANDLE_SIZE, DRAG_HANDLE_SIZE));
    Rectangle E = new Rectangle(
        new Point(control.Location.X + control.Width, 
            control.Location.Y + control.Height / 2 - DRAG_HANDLE_SIZE / 2), 
        new Size(DRAG_HANDLE_SIZE, DRAG_HANDLE_SIZE));
    Rectangle SW = new Rectangle(
        new Point(control.Location.X - DRAG_HANDLE_SIZE, 
            control.Location.Y + control.Height), 
        new Size(DRAG_HANDLE_SIZE, DRAG_HANDLE_SIZE));
    Rectangle S = new Rectangle(
        new Point(control.Location.X + control.Width / 2 - DRAG_HANDLE_SIZE/2, 
            control.Location.Y + control.Height), 
        new Size(DRAG_HANDLE_SIZE, DRAG_HANDLE_SIZE));
    Rectangle SE = new Rectangle(
        new Point(control.Location.X + control.Width, 
            control.Location.Y + control.Height), 
        new Size(DRAG_HANDLE_SIZE, DRAG_HANDLE_SIZE));

    //get the form graphic
    Graphics g = this.CreateGraphics();
    //draw the border and drag handles
    ControlPaint.DrawBorder(g, Border, Color.Gray, ButtonBorderStyle.Dotted);
    ControlPaint.DrawGrabHandle(g, NW, true, true);
    ControlPaint.DrawGrabHandle(g, N, true, true);
    ControlPaint.DrawGrabHandle(g, NE, true, true);
    ControlPaint.DrawGrabHandle(g, W, true, true);
    ControlPaint.DrawGrabHandle(g, E, true, true);
    ControlPaint.DrawGrabHandle(g, SW, true, true);
    ControlPaint.DrawGrabHandle(g, S, true, true);
    ControlPaint.DrawGrabHandle(g, SE, true, true);
    g.Dispose();
}

Next, implement the various events of the Control object, for example, when I click on a control, I want a border and drag handles drawn around it, so in the MouseDown event:

C#
private void control_MouseDown(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        this.Invalidate();  //unselect other control
        SelectedControl = (Control)sender;
        Control control = (Control)sender;
        mouseX = -e.X;
        mouseY = -e.Y;
        control.Invalidate();
        DrawControlBorder(sender);
        propertyGrid1.SelectedObject = SelectedControl;
    }  
}

Finally, to use it, create a control at runtime and have it subscribe to the various events, for example to create a button:

C#
Button ctrl = new Button();
ctrl.Text = "New Button";
ctrl.Location = new Point(50, 50);
ctrl.MouseEnter += new EventHandler(control_MouseEnter);
ctrl.MouseLeave += new EventHandler(control_MouseLeave);
ctrl.MouseDown += new MouseEventHandler(control_MouseDown);
ctrl.MouseMove += new MouseEventHandler(control_MouseMove);
ctrl.MouseUp += new MouseEventHandler(control_MouseUp);
Controls.Add(ctrl);

That's it. When executed, you can move the objects around, resize them in all 8 directions.

Points of Interest

If you download the source code, you'll notice that I use a timer to track the movement of the cursor. I tried to use the MouseHover event of the form, but that executed only once when the cursor is over it or when it leaves one of the controls, and subsequently when the cursor is over one of the drag handles it will fail to recognize it. Using a timer does solve this problem, but if you have found a better way please let me know!

History

  • 3/4/2008: First released

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionIt's great! Pin
Member 1122102310-Jan-15 13:32
Member 1122102310-Jan-15 13:32 
QuestionInstead of Timer Pin
vbjay.net4-Jan-15 7:49
vbjay.net4-Jan-15 7:49 
Use MouseEnter/Leave to set a flag and invalidate the control.
Questionrate Pin
David Narciso20-Jan-14 5:11
David Narciso20-Jan-14 5:11 
QuestionSolution For No overload for 'Control_mouseDown' match delegates 'system.eventHandler'. Pin
Jadhav Gangadhar7-Nov-12 0:01
Jadhav Gangadhar7-Nov-12 0:01 
GeneralMy vote of 5 Pin
Kshitiz Chandra11-Oct-12 19:27
Kshitiz Chandra11-Oct-12 19:27 
QuestionMy vote of 5 Pin
dl4gbe14-Sep-12 7:43
dl4gbe14-Sep-12 7:43 
GeneralMy vote of 5 Pin
Armando de la Torre18-Oct-11 15:49
Armando de la Torre18-Oct-11 15:49 
GeneralEliminated use of timer by adding to Form1_MouseMove event Pin
Jonathan Leung31-Aug-10 6:22
Jonathan Leung31-Aug-10 6:22 
GeneralRe: Eliminated use of timer by adding to Form1_MouseMove event Pin
momo.l10-Dec-10 17:59
momo.l10-Dec-10 17:59 
GeneralRe: Eliminated use of timer by adding to Form1_MouseMove event Pin
Hesham Eraqi18-Jul-14 1:11
Hesham Eraqi18-Jul-14 1:11 
GeneralRe: Eliminated use of timer by adding to Form1_MouseMove event Pin
Member 116423253-May-15 0:01
Member 116423253-May-15 0:01 
QuestionDrawGrabHandle doesn't work on panel ? Pin
kenlos27-Oct-08 17:00
kenlos27-Oct-08 17:00 
GeneralAllowing drag drop onto a panel Pin
alias4714-Apr-08 0:55
alias4714-Apr-08 0:55 
GeneralRe: Allowing drag drop onto a panel Pin
wliao14-Apr-08 2:21
wliao14-Apr-08 2:21 
GeneralRe: Allowing drag drop onto a panel Pin
alias4714-Apr-08 11:01
alias4714-Apr-08 11:01 
GeneralRe: Allowing drag drop onto a panel Pin
KNH Prod4-Jul-08 17:02
KNH Prod4-Jul-08 17:02 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.