15

i just wanted to put a selection on my picturebox.image but this has just become worse than some little annoying situation. I thought on another picture box over the main picturebox but it seemed so lazy work to me. I need to know if there is a way to create a selection area (which is gonna be half transparent blue area) on a picturebox.image which im gonna draw with mouse and it shouldnt change the image im working on.

sample:

    // Start Rectangle
    //
    private void pictureBox1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
    {
        // Determine the initial rectangle coordinates...
        RectStartPoint = e.Location;
        Invalidate();
    }

    // Draw Rectangle
    //
    private void pictureBox1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
    {
        if (e.Button != MouseButtons.Left)
            return;
        Point tempEndPoint = e.Location;
        Rect =
            new Rectangle(
                Math.Min(RectStartPoint.X, tempEndPoint.X),
                Math.Min(RectStartPoint.Y, tempEndPoint.Y),
                Math.Abs(RectStartPoint.X - tempEndPoint.X),
                Math.Abs(RectStartPoint.Y - tempEndPoint.Y));
        Invalidate(Rect);
    }

    // Draw Area
    //
    private void pictureBox1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
    {
        // Draw the rectangle...
        if (pictureBox1.Image != null)
        {
            Brush brush = new SolidBrush(Color.FromArgb(128, 72, 145, 220));
            e.Graphics.FillRectangle(brush, Rect);
        }
    }
Emond
  • 50,210
  • 11
  • 84
  • 115
Berker Yüceer
  • 7,026
  • 18
  • 68
  • 102
  • So do you want to create a selection box on an image in a pictureBox? Will the selection box act the same as clicking and dragging on the desktop to create a transparent blue square? – matthewr Jun 18 '12 at 09:24

2 Answers2

40

I used your code, you were nearly there. You needed to Invalidate the pictureBox1 instead of the rectangle. I also added a check for the Rect so it doesn't get drawn when it's not initialized or has no size.

Another important change: I created the Rectangle only once and I adjusted its location and size. Less garbage to clean up!

EDIT

I added a mouse right-click handler for the Rectangle.

private Point RectStartPoint;
private Rectangle Rect = new Rectangle();
private Brush selectionBrush = new SolidBrush(Color.FromArgb(128, 72, 145, 220));

// Start Rectangle
//
private void pictureBox1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
    // Determine the initial rectangle coordinates...
    RectStartPoint = e.Location;
    Invalidate();
}

// Draw Rectangle
//
private void pictureBox1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
    if (e.Button != MouseButtons.Left)
        return;
    Point tempEndPoint = e.Location;
    Rect.Location = new Point(
        Math.Min(RectStartPoint.X, tempEndPoint.X),
        Math.Min(RectStartPoint.Y, tempEndPoint.Y));
    Rect.Size = new Size(
        Math.Abs(RectStartPoint.X - tempEndPoint.X),
        Math.Abs(RectStartPoint.Y - tempEndPoint.Y));
    pictureBox1.Invalidate();
}

// Draw Area
//
private void pictureBox1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
    // Draw the rectangle...
    if (pictureBox1.Image != null)
    {
        if (Rect != null && Rect.Width > 0 && Rect.Height > 0)
        {
            e.Graphics.FillRectangle(selectionBrush, Rect);
        }
    }
}

private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Right)
    {
        if (Rect.Contains(e.Location))
        {
            Debug.WriteLine("Right click");
        }
    }
}
Emond
  • 50,210
  • 11
  • 84
  • 115
  • also can you tell me how can i create a right click event on that selection? – Berker Yüceer Jun 18 '12 at 07:54
  • 1
    BTW: In your implementation the brush is created again and again. Try to prevent that. I'll adjust my code for that as well. – Emond Jun 18 '12 at 08:35
  • Why is it a problem that the brush is created again and again? Is it an expensive operation? – kdbanman Aug 18 '15 at 16:26
  • 1
    @kdbanman - Yes. apart from it being superfluous, Brushes claim unmanaged resources. When you do not dispose these brushes (and other GDI objects) this memory will still be allocated. Depending on how often the mouse moves the code could thus leak quite some memory. See also this answer: http://stackoverflow.com/a/1336752/563088 – Emond Aug 18 '15 at 18:20
  • Thanks for the detail! One more question... Why the `Invalidate()` call in the mouse down handler, and the `pictureBox1.Invalidate()` call in mouse move handler? – kdbanman Aug 21 '15 at 15:32
  • 1
    @kdbanman - `Invalidate()` causes a redraw of the PictureBox. the redraw calls raises the Paint event and the Paint event handler draws the rectangle. The nice thing about this solution is that whenever the PictureBox is redraw (moved, resized, scaled, ...) the rectangle will follow and will always be insync. Besides, the Paint eventhandler receives a reference to the graphics object that is needed to draw the rectangle, so we do not have to create (and dispose) a grapics object ourselves. – Emond Aug 21 '15 at 19:31
  • I have implemented this code. But I cannot draw rectangle on my picture. It can be paint on picturebox. I cannot bring to front.please help. – Adem Aygun Aug 04 '17 at 13:23
  • @AdemAyg - Sorry, you cannot ask questions in the comments. If you create a new question that clearly demonstrates the problem I am happy to have a look at it. Make sure you post a minimal working example that shows the problem – Emond Aug 04 '17 at 16:19
  • @ErnodeWeerd here is the question: https://stackoverflow.com/questions/45546107/selecting-an-area-on-a-picturebox-with-mouse-in-c-sharp – Adem Aygun Aug 07 '17 at 11:43
-2
   private int xUp, yUp, xDown,yDown;
        private Rectangle rectCropArea;
   private void SrcPicBox_MouseUp(object sender, MouseEventArgs e)
        {
            //pictureBox1.Image.Clone();
            xUp = e.X;
            yUp = e.Y;
            Rectangle rec = new Rectangle(xDown,yDown,Math.Abs(xUp xDown),Math.Abs(yUp-yDown));
            using (Pen pen = new Pen(Color.YellowGreen, 3))
            {

                SrcPicBox.CreateGraphics().DrawRectangle(pen, rec);
            }
            rectCropArea = rec;
        }
 private void SrcPicBox_MouseDown(object sender, MouseEventArgs e)
        {
            SrcPicBox.Invalidate();

            xDown = e.X;
            yDown = e.Y;
        }
 private void btn_upload_Click(object sender, EventArgs e)
        {
            OpenFileDialog opf = new OpenFileDialog();
          //  PictureBox SrcPicBox = new PictureBox();
            opf.Filter = "ALL images(*.*)|*.*";
            if (opf.ShowDialog() == DialogResult.OK)
            {
                string name = opf.SafeFileName;
                string filepath = opf.FileName;
                File.Copy(filepath, name, true);
                SrcPicBox.Image = Image.FromFile(opf.FileName);
            }
 private void btn_crop_Click(object sender, EventArgs e)
        {
            pictureBox3.Refresh();
            //Prepare a new Bitmap on which the cropped image will be drawn
            Bitmap sourceBitmap = new Bitmap(SrcPicBox.Image, SrcPicBox.Width, SrcPicBox.Height);
            Graphics g = pictureBox3.CreateGraphics();

            //Draw the image on the Graphics object with the new dimesions
            g.DrawImage(sourceBitmap, new Rectangle(0, 0, pictureBox3.Width, pictureBox3.Height), rectCropArea, GraphicsUnit.Pixel);
            sourceBitmap.Dispose();
        }
  • 7
    Please add some description what your code does and how it provides an answer to the question. – Klaus Gütter Jan 10 '19 at 14:20
  • 2
    We appreciate that you've taken time to provide a solution, However, a good answer should also have some description as to why it would solve the problem of the OP, and if possible, point the exact things the OP needs to address. Scrolling large fragments of code usually turns folks off. Try editing to make it more usable both to the OP and the community here. – Ivaylo Slavov Jan 10 '19 at 22:08
  • I had to change=> this line: Bitmap sourceBitmap = new Bitmap(SrcPicBox.Image, SrcPicBox.Width, SrcPicBox.Height); to: Bitmap sourceBitmap = new Bitmap(SrcPicBox.Image, SrcPicBox.Image.Width, SrcPicBox.Image.Height); in order to get proper result. – Koorosh Oct 18 '19 at 16:37