-1

I have a panel containing multiple picturebox.

I want to give users the option of selecting any part of any picturebox.

The user will select it by mouse.

I want to draw a semi-transparent rectangle on the picturebox while the mouse move as per the selection.

The code is working fine, but the rectangle is flickering. I want to stop the flickering.

I tried double buffer using how to stop flickering C# winforms

Also, added Invalide using How to force graphic to be redrawn with the invalidate method

But not working. Please help.

My Code:

private Brush selectionBrush = new SolidBrush(Color.FromArgb(70, 76, 255, 0));

private void Picture_MouseMove(object sender, MouseEventArgs e)
{
    if (e.Button != MouseButtons.Left) return;

    PictureBox pb = (PictureBox)(sender);

    Point tempEndPoint = e.Location;
    Rect.Location = new Point(
        Math.Min(RecStartpoint.X, tempEndPoint.X),
        Math.Min(RecStartpoint.Y, tempEndPoint.Y));
    Rect.Size = new Size(
        Math.Abs(RecStartpoint.X - tempEndPoint.X),
        Math.Abs(RecStartpoint.Y - tempEndPoint.Y));

    pb.CreateGraphics().FillRectangle(selectionBrush, Rect);
    pb.Invalidate(Rect);
}
Community
  • 1
  • 1
Danish Khan
  • 63
  • 1
  • 7
  • 3
    what if you remove `pb.Invalidate(Rect);` – Lei Yang May 18 '17 at 06:38
  • @LeiYang The rectangle drawn is without transparency and doesn't disappear on mouse up. – Danish Khan May 18 '17 at 06:39
  • i guess you need paint all/part in `Paint` event, and in that way you can call `Invalidate` in other button events. – Lei Yang May 18 '17 at 06:41
  • It's better do painting works in Paint handler. You should change your approach. – DotNet Developer May 18 '17 at 06:42
  • 2
    what about that question you asked yesterday? The one where i gave you an [example how to clear rectangle](http://stackoverflow.com/questions/44021201/c-sharp-imagebox-clear-rectangle-on-mouseup) on `MouseUp`? You'll keep asking questions until someone writes you application? – Nino May 18 '17 at 06:43
  • I even tried private void Picture_Paint(object sender, PaintEventArgs e) { PictureBox pb = (PictureBox)(sender); if (Rect!=null && Rect.Width>0 && Rect.Height>0) { pb.CreateGraphics().FillRectangle(selectionBrush, Rect); } } and added PictureBox org_pic = (PictureBox)(sender); org_pic.Invalidate(Rect); in mouse Up event but cant see the rectangle. – Danish Khan May 18 '17 at 06:43
  • in `Paint` you just use `e.Graphics`, not create it again. – Lei Yang May 18 '17 at 06:46
  • @LeiYang I even tried e.Graphics.FillRectangle(selectionBrush, Rect); But got below issues with it, The rectangle doesntnt disappear at mouseup, the rectangle is shown at the end not on mouse movement. Plus, the rectangle is automatically drawn on all picture boxes in the panel. – Danish Khan May 18 '17 at 06:50
  • I'm not quite sure what you mean by 'doesntnt disappear', in `Paint` you should draw every thing you need again, if you need some thing to disappear, then don't draw it. you may need some private variables to store data to draw. – Lei Yang May 18 '17 at 06:53
  • @LeiYangThe store the original image and restore it successfully. But as I am using e.Graphics when I scroll the panel the rectangle is drawn on the other picture boxes automatically. – Danish Khan May 18 '17 at 07:15
  • @nino I have replied on the issue I'm facing in the approach suggested by you. – Danish Khan May 18 '17 at 07:16
  • To draw live-rectangle you indeed need __not__ use the Paint event but use pb.creategraphics. call refresh before and no invalidate after. Try using DrawRectanlge, not fill so you don't draw too many pixels. [Here is an example](http://stackoverflow.com/questions/32019439/c-sharp-how-to-draw-a-rubber-band-selection-rectangle-on-panel-like-one-used-in/39179990?s=2|2.3975#39179990) – TaW May 18 '17 at 07:24
  • . Note that the __golden rule__ of never creating a graphics from a control doen't apply for non-persistent stuff. For persistent drawing see [here](http://stackoverflow.com/questions/26829667/how-to-draw-a-rubber-band-selection-rectangle-accurately-on-a-rotated-canvas/26830239?s=1|2.5606#26830239). Note that you (proably) can ignore the part about scaling/rotating.. – TaW May 18 '17 at 07:27

2 Answers2

2

This does not address the PictureBox, but maybe helps.

First I replaced the PictureBox with Panel which can also be used to draw pictures. Next I activated double buffering:

somewhere in the namespace add this class:

class DoubleBufferedPanel : Panel 
{ 
    public DoubleBufferedPanel() : base() 
    { 
        DoubleBuffered = true; 
    } 
 }

and then replace in Form1.Designer.cs all "System.Windows.Forms.Panel" with "DoubleBufferedPanel".

this works fine in many of my graphical applications.

harry4516
  • 193
  • 8
1

You indicate the Double Buffering solution doesn't work for you, did you find out why? Because the following custom control draws a sizable rectangle on the picturebox without the flicker:

public class TryDoubleBufferAgain : PictureBox
{
    public TryDoubleBufferAgain()
    {
        this.DoubleBuffered = true;
        this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
        this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
        this.UpdateStyles();
    }
    protected override void OnMouseMove(MouseEventArgs e)
    {
        this.Refresh();
        base.OnMouseMove(e);
    }
    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);

        // Edit below to actually  draw a usefull rectangle
        e.Graphics.DrawRectangle(System.Drawing.Pens.Red, new System.Drawing.Rectangle(0, 0, Cursor.Position.X, Cursor.Position.Y));
    }
}
Fixation
  • 969
  • 6
  • 12