Create events for ControlPaint.DrawGrabHandle

SEVI

Well-known member
Joined
Jun 28, 2003
Messages
48
Location
Australia
Trying to use grab handles to resize a picturebox at runtime, se below. No problem drawing the grab handles but I cant figure out how to wire the grab handles to the respective events.

Any ideas??

Thanks..

DrawGH(System.Windows.Forms.PictureBox p) {

const int hdlSz = 10;
System.Drawing.Graphics g = p.CreateGraphics();
System.Drawing.Point p = new System.Drawing.Point(0,0);
System.Drawing.Size s = new System.Drawing.Size(p.Width,p.Height);
System.Drawing.Rectangle r = new System.Drawing.Rectangle(p,s);
System.Drawing.Rectangle rHandle;
rHandle = new System.Drawing.Rectangle(r.X, r.Y, hdlSz, hdlSz);
System.Windows.Forms.ControlPaint.DrawGrabHandle(g, rHandle, true, true);
rHandle = new System.Drawing.Rectangle(r.X + r.Width/2 - hdlSz/2, r.Y, hdlSz, hdlSz);
System.Windows.Forms.ControlPaint.DrawGrabHandle(g, rHandle, true, true);
rHandle = new System.Drawing.Rectangle(r.X + r.Width - hdlSz, r.Y, hdlSz, hdlSz);
System.Windows.Forms.ControlPaint.DrawGrabHandle(g, rHandle, true, true);
rHandle = new System.Drawing.Rectangle(r.X, r.Y + r.Height/2 - hdlSz/2, hdlSz, hdlSz);
System.Windows.Forms.ControlPaint.DrawGrabHandle(g, rHandle, true, true);
rHandle = new System.Drawing.Rectangle(r.X + r.Width - hdlSz, r.Y + r.Height/2 - hdlSz/2, hdlSz, hdlSz);
System.Windows.Forms.ControlPaint.DrawGrabHandle(g, rHandle, true, true);
rHandle = new System.Drawing.Rectangle(r.X, r.Y + r.Height - hdlSz, hdlSz, hdlSz);
System.Windows.Forms.ControlPaint.DrawGrabHandle(g, rHandle, true, true);
rHandle = new System.Drawing.Rectangle(r.X + r.Width/2 - hdlSz/2, r.Y + r.Height - hdlSz, hdlSz, hdlSz);
System.Windows.Forms.ControlPaint.DrawGrabHandle(g, rHandle, true, true);
rHandle = new System.Drawing.Rectangle(r.X - hdlSz + r.Width, r.Y + r.Height - hdlSz, hdlSz, hdlSz);
System.Windows.Forms.ControlPaint.DrawGrabHandle(g, rHandle, true, true);

}
 
There arent any events, you have to write all the code to do this yourself. All the framework does is provide methods for drawing the handles.
 
Hi,

Youve got a few options:

1) The Messy Approach (tm) - draw them as you are doing and test in your control/forms OnMouseMove to see if the mouse is over them (change the cursor appropriately). You also need OnMouseDown to start dragging and OnMouseUp to stop. OnMouseMove will check to see if your bool (set in OnMouseDown) is set and change the picturebox appropriately. I *strongly* advise against this approach.

2) The Clean Approach - Write a GrabHandle custom control (hint: derive from Control). This control can set an appropriate cursor just using its (inherited) Cursor property, and you can pass in the type of cursor it will use to the constructor. The MouseDown/Up events can be caught from the containing control/form and dragging can be taken care of appropriately. This is the most difficult approach and might be too complex if the overall task you are trying to achieve is a small one.

3) The Hybrid Approach - Create a new class (or even a struct!) which will contain a Rectangle with the coords of the grab handle, the type of cursor to draw when the mouse is over it and a method to update the coords (to the current ClientRectangle). You can use properties to access the rectangle and update it before use automatically. The advantage of all this is that now youre OnMouseMove override can use the Rectangle.Contains method (instead of testing points yourself) and so a lot of your code will be cleaner. This is my preferred method for small/medium sized projects as it has a nice tradeoff of simplicity and functionality.

Sorry for the wordy reply, but I dealt with something similar recently and felt it needed saying ;)

Pete
 
Excellent info.. thanx.. but I am struggling a little bit though as Id like to go option 2 and encapsulate everything in a class. But I dont understand how I can create mousemove, mouse down etc events for the handles when they have no user interface. Ie the rectangle that forms the base of the handle point itself has little events associated with it. Do I have to create another rectangle class that has the mouse events enabled. I have created a class to draw out the handles but have not associated an objedct with that class as such.. see below.. I mean it works but as Pete mentions its not pretty..

public class clsGrabHandles : System.Windows.Forms.UserControl {
private const int hdlSz = 10;
private bool bResize = false;

public clsGrabHandles() {
}

public clsGrabHandles(clsImage i) {
DrawHandlesOnPath(i);
}

public clsGrabHandles(clsImage i, System.Drawing.Point p) {
DrawHandlesOnPath(i,p);
}

public bool Resizing {
get {
return bResize;
}
set {
bResize = value;
}
}

private void DrawHandlesOnPath(clsImage i, System.Drawing.Point p) {

//Create graphics object
System.Drawing.Graphics g = i.CreateGraphics();
//Get the paths bounding rectangle
System.Drawing.Rectangle r = new System.Drawing.Rectangle(new System.Drawing.Point(0,0),new System.Drawing.Size(i.Width,i.Height));
//Top left
System.Drawing.Rectangle rHandleTL = new System.Drawing.Rectangle(r.X, r.Y, hdlSz, hdlSz);
System.Windows.Forms.ControlPaint.DrawGrabHandle(g, rHandleTL, true, true);
//Top center
System.Drawing.Rectangle rHandleTC = new System.Drawing.Rectangle(r.X + r.Width/2 - hdlSz/2, r.Y, hdlSz, hdlSz);
System.Windows.Forms.ControlPaint.DrawGrabHandle(g, rHandleTC, true, true);
//Top right
System.Drawing.Rectangle rHandleTR = new System.Drawing.Rectangle(r.X + r.Width - hdlSz, r.Y, hdlSz, hdlSz);
System.Windows.Forms.ControlPaint.DrawGrabHandle(g, rHandleTR, true, true);
//Left center
System.Drawing.Rectangle rHandleLC = new System.Drawing.Rectangle(r.X, r.Y + r.Height/2 - hdlSz/2, hdlSz, hdlSz);
System.Windows.Forms.ControlPaint.DrawGrabHandle(g, rHandleLC, true, true);
//Right center
System.Drawing.Rectangle rHandleRC = new System.Drawing.Rectangle(r.X + r.Width - hdlSz, r.Y + r.Height/2 - hdlSz/2, hdlSz, hdlSz);
System.Windows.Forms.ControlPaint.DrawGrabHandle(g, rHandleRC, true, true);
//Bottom left
System.Drawing.Rectangle rHandleBL = new System.Drawing.Rectangle(r.X, r.Y + r.Height - hdlSz, hdlSz, hdlSz);
System.Windows.Forms.ControlPaint.DrawGrabHandle(g, rHandleBL, true, true);
//Bottom center
System.Drawing.Rectangle rHandleBC = new System.Drawing.Rectangle(r.X + r.Width/2 - hdlSz/2, r.Y + r.Height - hdlSz, hdlSz, hdlSz);
System.Windows.Forms.ControlPaint.DrawGrabHandle(g, rHandleBC, true, true);
//Bottom right
System.Drawing.Rectangle rHandleBR = new System.Drawing.Rectangle(r.X - hdlSz + r.Width, r.Y + r.Height - hdlSz, hdlSz, hdlSz);
System.Windows.Forms.ControlPaint.DrawGrabHandle(g, rHandleBR, true, true);

if (rHandleTL.Contains(p)){
System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.SizeNWSE;

} else if (rHandleTC.Contains(p)){
System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.SizeNS;
this.Resizing = true;
} else if (rHandleTR.Contains(p)){
System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.SizeNESW;
this.Resizing = true;
} else if (rHandleLC.Contains(p)){
System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.SizeWE;
this.Resizing = true;
} else if (rHandleRC.Contains(p)){
System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.SizeWE;
this.Resizing = true;
} else if (rHandleBL.Contains(p)){
System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.SizeNESW;
this.Resizing = true;
} else if (rHandleBC.Contains(p)){
System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.SizeNS;
this.Resizing = true;
} else if (rHandleBR.Contains(p)){
System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.SizeNWSE;
this.Resizing = true;
} else {
System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.Hand;
this.Resizing = false;
}
}

private void DrawHandlesOnPath(clsImage i) {

//Create graphics object
System.Drawing.Graphics g = i.CreateGraphics();
//Get the paths bounding rectangle
System.Drawing.Rectangle r = new System.Drawing.Rectangle(new System.Drawing.Point(0,0),new System.Drawing.Size(i.Width,i.Height));
//Top left
System.Drawing.Rectangle rHandleTL = new System.Drawing.Rectangle(r.X, r.Y, hdlSz, hdlSz);
System.Windows.Forms.ControlPaint.DrawGrabHandle(g, rHandleTL, true, true);
//Top center
System.Drawing.Rectangle rHandleTC = new System.Drawing.Rectangle(r.X + r.Width/2 - hdlSz/2, r.Y, hdlSz, hdlSz);
System.Windows.Forms.ControlPaint.DrawGrabHandle(g, rHandleTC, true, true);
//Top right
System.Drawing.Rectangle rHandleTR = new System.Drawing.Rectangle(r.X + r.Width - hdlSz, r.Y, hdlSz, hdlSz);
System.Windows.Forms.ControlPaint.DrawGrabHandle(g, rHandleTR, true, true);
//Left center.
System.Drawing.Rectangle rHandleLC = new System.Drawing.Rectangle(r.X, r.Y + r.Height/2 - hdlSz/2, hdlSz, hdlSz);
System.Windows.Forms.ControlPaint.DrawGrabHandle(g, rHandleLC, true, true);
//Right center.
System.Drawing.Rectangle rHandleRC = new System.Drawing.Rectangle(r.X + r.Width - hdlSz, r.Y + r.Height/2 - hdlSz/2, hdlSz, hdlSz);
System.Windows.Forms.ControlPaint.DrawGrabHandle(g, rHandleRC, true, true);
//Bottom left.
System.Drawing.Rectangle rHandleBL = new System.Drawing.Rectangle(r.X, r.Y + r.Height - hdlSz, hdlSz, hdlSz);
System.Windows.Forms.ControlPaint.DrawGrabHandle(g, rHandleBL, true, true);
//Bottom center.
System.Drawing.Rectangle rHandleBC = new System.Drawing.Rectangle(r.X + r.Width/2 - hdlSz/2, r.Y + r.Height - hdlSz, hdlSz, hdlSz);
System.Windows.Forms.ControlPaint.DrawGrabHandle(g, rHandleBC, true, true);
//Bottom right.
System.Drawing.Rectangle rHandleBR = new System.Drawing.Rectangle(r.X - hdlSz + r.Width, r.Y + r.Height - hdlSz, hdlSz, hdlSz);
System.Windows.Forms.ControlPaint.DrawGrabHandle(g, rHandleBR, true, true);
}
}
 
Hi,

With option 2 I meant you should make a new control with what you need:

C#:
// GrabHandle encapsulates a single grab handle
class GrabHandle : Control
{
    protected override OnPaint( PaintEventArgs e )
    {
        // Do your DrawGrabHandle stuff here, using e.Graphics.
        // Remember to give the size as ClientRectangle, so the
        // control will draw itself to the size its parent form needs
    }

    protected override OnMouseDown( MouseEventArgs e )
    {
        // You are here if the mouse was pressed while over the
        // GrabHandle. This is where you can set a bool that will
        // tell your MouseMove event to do the resizing, etc.

        // Because you only get mouse events here while actually
        // over the control, it MIGHT be best to use the MouseMove
        // event of the parent control (probably your form), in
        // which case it is not necessary to set a bool, just do:
        Parent.MouseMove += new MouseEventHandler( HandleMouseMove );

        // Now we also need MouseUp.. you might get away with an
        // override of OnMouseUp (since the GrabHandle will move
        // with the MouseMove event. To be safe, you could do:
        Parent.MouseUp += new MouseEventHandler( HandleMouseUp );

        // In order to draw our rubber band effect on the parent
        // form we need to handle its Paint event:
        Parent.Paint += new PaintEventHandler( HandlePaint );
    }

    private void HandleMouseMove( object sender,
                                  MouseEventArgs e )
    {
        // Here you need to store the mouse coordinates for drawing
        // inside the Parent Controls paint event (as a rubber band).
    }

    private void HandleMouseUp( object sender,
                                MouseEventArgs e )
    {
        // Here you need to remove the event handlers that got
        // attached in OnMouseDown, so we arent still getting
        // these when the control does not need them. I think
        // this approach works:
        Parent.MouseMove -= new MouseEventHandler( HandleMouseMove );
        Parent.MouseUp -= new MouseEventHandler( HandleMouseUp );
        Parent.Paint -= new PaintEventHandler( HandlePaint );

        // Here you also need to resize the picture Control and
        // move the relevant handles.. not sure how you could
        // accomplish this (hold references to them or locate them
        // somehow?).
    }

    private void HandlePaint( object sender,
                              PaintEventArgs e )
    {
        // Here you use the mouse coordinates to draw the rubber
        // band effect. This can be done with the draw reversible
        // method (I forget the name), or with a TextureBrush, or
        // however you like.
    }
}

Thats how Id imagined it. Ill leave details/improvements up to you.

Hope that helps,
Pete
 
Err.. make that a public class.. and remember to check which mouse button was pressed in OnMouseDown (and that only one Click was used).

Pete
 
Back
Top