Question how to provide resize feature based on the mouse wheel up and down to a shape on the picture box

thippu

Active member
Joined
Mar 6, 2019
Messages
27
Location
Bangalore
Programming Experience
Beginner
Hi,
1. I have a picture box and I have drawn a rectangle shape.
2. If a user clicks on the shape, I can know a shape is clicked or not and based on the stored coordinates.
3. Now I want to provide the resize feature on the shape by using a mouse wheel event(scaling the shape), it can be up or down.
4. I have registered an event

Picture box mouse wheel event:
Private void PictureBoxImage_MouseWheel(object sender, MouseEventArgs e)
{
    
}

5. I will create a Matrix object but on the Scale method what value to pass, Scale method link? Can I get some idea from u?
 
This is the sort of thing you want:
C#:
private float scale = 1.0F;

private void Form1_Load(object sender, EventArgs e)
{
    pictureBox1.MouseWheel += PictureBox1_MouseWheel;
    pictureBox1.Paint += PictureBox1_Paint;
}

private void PictureBox1_MouseWheel(object sender, MouseEventArgs e)
{
    // Scale in 0.1 increments down to a minimum of 0.1.
    scale = Math.Max(scale + Math.Sign(e.Delta) * 0.1F, 0.1F);

    pictureBox1.Refresh();
}

private void PictureBox1_Paint(object sender, PaintEventArgs e)
{
    var matrix = new Matrix();

    matrix.Scale(scale, scale, MatrixOrder.Append);

    e.Graphics.Transform = matrix;
    e.Graphics.DrawRectangle(Pens.Black, 10, 10, 50, 100);
}
That uses the same scale value in both the X and Y directions, thus retaining the aspect ratio. For each notch the user turns the wheel up, the scale increases by 0.1. Similarly, it decreases by 0.1 for each notch down, down to a minimum of 0.1.
 
This is the sort of thing you want:
C#:
private float scale = 1.0F;

private void Form1_Load(object sender, EventArgs e)
{
    pictureBox1.MouseWheel += PictureBox1_MouseWheel;
    pictureBox1.Paint += PictureBox1_Paint;
}

private void PictureBox1_MouseWheel(object sender, MouseEventArgs e)
{
    // Scale in 0.1 increments down to a minimum of 0.1.
    scale = Math.Max(scale + Math.Sign(e.Delta) * 0.1F, 0.1F);

    pictureBox1.Refresh();
}

private void PictureBox1_Paint(object sender, PaintEventArgs e)
{
    var matrix = new Matrix();

    matrix.Scale(scale, scale, MatrixOrder.Append);

    e.Graphics.Transform = matrix;
    e.Graphics.DrawRectangle(Pens.Black, 10, 10, 50, 100);
}
That uses the same scale value in both the X and Y directions, thus retaining the aspect ratio. For each notch the user turns the wheel up, the scale increases by 0.1. Similarly, it decreases by 0.1 for each notch down, down to a minimum of 0.1.
Bro, Can it be scaled without moving it?
mean: we will scale to shape after that it scales and translates to some other position on the picture box, can we scale on the original position, right now it feels like scaling and also translating?
 
You're not just scaling the rectangle but the entire canvas. That code draws the top, left corner at 10 pixels below and 10 pixels right of the origin so those values will also be scaled. If you don't want the top, left corner of the rectangle to move when the canvas is scaled then you have to draw it at the origin, which means that you need to translate the origin to where you want the top left corner to be drawn. In the code below, instead of drawing the corner 10 pixels down and 10 pixels right, the origin is translated 10 pixels down and 10 pixels right and the corner is drawn at the origin. You have to do the translation after the scaling, which I think is counter-intuitive but that's the way it works.
C#:
private float scale = 1.0F;

private void Form1_Load(object sender, EventArgs e)
{
    pictureBox1.MouseWheel += PictureBox1_MouseWheel;
    pictureBox1.Paint += PictureBox1_Paint;
}

private void PictureBox1_MouseWheel(object sender, MouseEventArgs e)
{
    // Scale in 0.1 increments down to a minimum of 0.1.
    scale = Math.Max(scale + Math.Sign(e.Delta) * 0.1F, 0.1F);

    pictureBox1.Refresh();
}

private void PictureBox1_Paint(object sender, PaintEventArgs e)
{
    var matrix = new Matrix();

    matrix.Scale(scale, scale, MatrixOrder.Append);
    matrix.Translate(10.0F, 10.0F, MatrixOrder.Append);

    e.Graphics.Transform = matrix;
    e.Graphics.DrawRectangle(Pens.Black, 0, 0, 50, 100);
}
 
Just note that the code above still scales the entire canvas so, if you're drawing multiple shapes, the others would still move. If you want to be able to scale multiple shapes without moving then you need to translate the origin prior to drawing each shape and then draw each one at the origin, e.g.
C#:
private float scale = 1.0F;

private void Form1_Load(object sender, EventArgs e)
{
    pictureBox1.MouseWheel += PictureBox1_MouseWheel;
    pictureBox1.Paint += PictureBox1_Paint;
}

private void PictureBox1_MouseWheel(object sender, MouseEventArgs e)
{
    // Scale in 0.1 increments down to a minimum of 0.1.
    scale = Math.Max(scale + Math.Sign(e.Delta) * 0.1F, 0.1F);

    pictureBox1.Refresh();
}

private void PictureBox1_Paint(object sender, PaintEventArgs e)
{
    var matrix = new Matrix();

    matrix.Scale(scale, scale, MatrixOrder.Append);
    matrix.Translate(10.0F, 10.0F, MatrixOrder.Append);

    e.Graphics.Transform = matrix;
    e.Graphics.DrawRectangle(Pens.Black, 0, 0, 50, 100);

    matrix.Translate(200.0F, 0.0F, MatrixOrder.Append);

    e.Graphics.Transform = matrix;
    e.Graphics.DrawRectangle(Pens.Black, 0, 0, 50, 100);
}
 
If you wanted to be able to scale multiple shapes separately then you'd have to store separate scale values for each shape and only modify the right one in the MouseWheel event handler, then create a new Matrix with the appropriate translation and scale before drawing each shape.
 
Other shapes are still, they are okay not getting affected by the scaled shape.
you are right I have to translate to the shape original position.
Thank you so much.
 
If you wanted to be able to scale multiple shapes separately then you'd have to store separate scale values for each shape and only modify the right one in the MouseWheel event handler, then create a new Matrix with the appropriate translation and scale before drawing each shape.

I included the code to project but some issues with my picturebox.Refresh(); I'm could able to spot the extra refresh on the picture box, help me.
code :
problem in my refresh code:
GraphicsPath path=new GraphicsPath();
private float scale=1.0F;
private bool ActiveWheel=false;
public Form1()
{
    path.AddRectangle(new Rectangle(0,0,50,100));
}
private void PictureBox1_Paint(object sender,PaintEventArgs e)
{
    if(ActiveWheel)
    {
        ActiveWheel=false;
        ScaleRectangle(e);
        pictureBox1.Invalidate();
    }
else
{
   e.Graphics.DrawPath(Pens.Red,path);
}
}
private void ScaleRectangle(PaintEventArgs e)
{
    var matrix=new Matrix();
    matrix.Scale(scale,scale,MatrixOrder.Append);
    path.Transform(matrix);
    e.Graphics.DrawPath(Pens.Blue,path);
}

please run the code : perform 5 mouse wheel ups and 2 mouse wheel downs, it will not decrease(scales down) but the shape is getting scaled up like on the mouse wheel up, what would be the problem?bro.
 
Don't call Invalidate in the Paint event handler. That's the method you call if you want to cause that event to be raised. If you cause the event to be raised each time it's raised, it will never stop being raised. Look at the code I provided. Do I ever do that? I call Refresh in the MouseWheel event handler, so that's where you would call Invalidate. Refresh calls Invalidate and then also calls Update, which causes the Paint event to be raised immediately rather than waiting until other queued events have been processed.
 
Don't call Invalidate in the Paint event handler. That's the method you call if you want to cause that event to be raised. If you cause the event to be raised each time it's raised, it will never stop being raised. Look at the code I provided. Do I ever do that? I call Refresh in the MouseWheel event handler, so that's where you would call Invalidate. Refresh calls Invalidate and then also calls Update, which causes the Paint event to be raised immediately rather than waiting until other queued events have been processed.
I changed the code from pictureBox1.Invalidate() to pictureBox1.Refresh() but the problem exists still.

code:
GraphicsPath path=new GraphicsPath();
private float scale=1.0F;
private bool ActiveWheel=false;
public Form1()
{
    path.AddRectangle(new Rectangle(0,0,50,100));
}
private void PictureBox1_Paint(object sender,PaintEventArgs e)
{
    if(ActiveWheel)
    {
        ActiveWheel=false;
        ScaleRectangle(e);
     //I removed the pictureBox1.Invalidate() from here also.
    }
else
{
   e.Graphics.DrawPath(Pens.Red,path);
}
    
}
private void PictureBox1_MouseWheel(object sender,MouseEventArgs e)
{
    ActiveWheel=true;
    scale=Math.Max(scale+Math.Sign(e.Delta)*0.1F,0.1F);
    pictureBox1.Refresh();
}
}
private void ScaleRectangle(PaintEventArgs e)
{
    var matrix=new Matrix();
    matrix.Scale(scale,scale,MatrixOrder.Append);
    path.Transform(matrix);
    e.Graphics.DrawPath(Pens.Blue,path);
}
 
Back
Top Bottom