Windows Develop Bookmark and Share   
 index > Windows Forms General > [C#] Rectangle Drawing not smooth
 

[C#] Rectangle Drawing not smooth

The following code puts a "red mask" over the form and when the rectangle "Rect" is drawn it erases the mask and shows the normal (unmasked) area. Its working very good.

But there's one problem. The drawing is not smooth. It takes about about a second to draw the rectangle when drag the mouse a little bit far from the startPos (start position). I want it to be smoother.

P.S: I've set doubleBuffer to true and also there's another app (not mine) that has the same mask thingy and its smoother. So its not my pc that has the problem. The problem is in the code:

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        Rectangle rect;
        Point startPos = Point.Empty;
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_MouseDown(object sender, MouseEventArgs e)
        {
            rect = new Rectangle(e.X, e.Y, 0, 0);
            startPos = e.Location;
            this.Invalidate();
        }

        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            if (startPos != Point.Empty)
            {
                rect = new Rectangle(rect.Left, rect.Top, e.X - rect.Left, e.Y - rect.Top);
                this.Invalidate();
            }
        }

        private void Form1_MouseUp(object sender, MouseEventArgs e)
        {
            startPos = Point.Empty;
        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {<br/>
            using (Brush br = new SolidBrush(Color.FromArgb(150, Color.Red)))
            {
                int x1 = rect.X; int x2 = rect.X + rect.Width;
                int y1 = rect.Y; int y2 = rect.Y + rect.Height;
                e.Graphics.FillRectangle(br, new Rectangle(0, 0, x1, this.Height));
                e.Graphics.FillRectangle(br, new Rectangle(x2, 0, this.Width - x2, this.Height));
                e.Graphics.FillRectangle(br, new Rectangle(x1, 0, x2 - x1, y1));
                e.Graphics.FillRectangle(br, new Rectangle(x1, y2, x2 - x1, this.Height - y2));
            }

            using (Pen pen = new Pen(Color.Red, 2))
            {
                e.Graphics.DrawRectangle(pen, rect);
            }
        }
    }
}
Thanks
farooqaaa  Wednesday, September 23, 2009 6:31 PM
I've tried resizing the form to some size instead of using Maximize with FormBorderStyle set to "true" and the rectangle is smooth!
I'll guess that you use the BackgroundImage property to display the image. That's is going to get slow if the image needs to be rescaled to fit the form. Override the OnResizeEnd() method of the form and re-create the image, make it exactly as large as ClientSize. Also make sure it is in the 32bppPArgb format, it is faster by a factor of 10 on most video hardware.

Hans Passant.
  • Marked As Answer byfarooqaaa Sunday, September 27, 2009 12:18 PM
  •  
nobugz  Friday, September 25, 2009 9:37 AM
The Mask Effect is taken from this thread:
http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/b59c014e-8c33-4f14-9181-058f2f499747

Thanks
farooqaaa  Wednesday, September 23, 2009 6:32 PM
Hi,

This may or may not help, but try setting the 'SmoothingMode' property of the graphics object in the paint event to a high quality setting (there is an enum for the possible values). That may smooth the edges out.
Yort  Wednesday, September 23, 2009 8:20 PM
It is silky smooth when I try your version. I can only guess that your video hardware isn't good enough. Beware that it flickers like a cheap motel when you don't turn on double buffering.

Hans Passant.
nobugz  Thursday, September 24, 2009 1:07 AM
Yeah, the above code is smooth for me too. But its smooth because I've extracted that from my app. And... I've already stated that I've doubleBuffering set to "True".

My app has No FormBorderStyle and covers the whole screen. And when the form loads it takes a screenshot and then uses it as the form background. After that the Mask is drawn over the form (i.e: over the screenshot ). When you draw with the mouse it erases the mask from the are you draw the rectangle on.

Here's the Form_Load code for my form:

private void Form2_Load(object sender, EventArgs e)<br/>
{<br/>
      back = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);<br/>
<br/>
      Graphics g = Graphics.FromImage(back);<br/>
      g.CopyFromScreen(new Point(0, 0), new Point(0, 0), Screen.PrimaryScreen.Bounds.Size);<br/>
      this.BackgroundImage = back;<br/>
}
farooqaaa  Thursday, September 24, 2009 6:57 AM
That's what my original code did as well. It was smooth, I recommend you use it.
Hans Passant.
nobugz  Thursday, September 24, 2009 9:44 AM
Yeah, I am using that code. But I want the slow-performance problem fixed. Its a little bit slow (not smooth).
farooqaaa  Thursday, September 24, 2009 2:36 PM
I've tried resizing the form to some size instead of using Maximize with FormBorderStyle set to "true" and the rectangle is smooth!

But I want the form to be maximized. Any one help me please?
farooqaaa  Friday, September 25, 2009 1:34 AM

Hi farooqaaa,

From my experience, the root cause of the low performance is that the MouseMove event would be fired very frequently, so the form would also be refreshed frequently. We can add a Timer to the form and handle its Ticket event to refresh the form. Then we are able to modify its Interval property to adjust the refresh frequency. This is the modified code snippet:

    public partial class Form5 : Form
    {
        Rectangle rect;
        Point startPos = Point.Empty;
        Timer timer = new Timer();
        public Form5()
        {
            InitializeComponent();

            //Set these styles to smooth the drawing.
            this.SetStyle(ControlStyles.UserPaint, true);
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);

            //You can modify the Interval property to adjust the refresh frequency.
            timer.Interval = 1000/24;
            timer.Tick += new EventHandler(timer_Tick);
            timer.Start();
        }

        void timer_Tick(object sender, EventArgs e)
        {
            //Refresh.
            this.Invalidate();
        }

        private void Form1_MouseDown(object sender, MouseEventArgs e)
        {
            rect = new Rectangle(e.X, e.Y, 0, 0);
            startPos = e.Location;
        }

        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            if (startPos != Point.Empty)
            {
                rect = new Rectangle(rect.Left, rect.Top, e.X - rect.Left, e.Y - rect.Top);
            }
        }

        private void Form1_MouseUp(object sender, MouseEventArgs e)
        {
            startPos = Point.Empty;
        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            using (Brush br = new SolidBrush(Color.FromArgb(150, Color.Red)))
            {
                int x1 = rect.X; int x2 = rect.X + rect.Width;
                int y1 = rect.Y; int y2 = rect.Y + rect.Height;
                e.Graphics.FillRectangle(br, new Rectangle(0, 0, x1, this.Height));
                e.Graphics.FillRectangle(br, new Rectangle(x2, 0, this.Width - x2, this.Height));
                e.Graphics.FillRectangle(br, new Rectangle(x1, 0, x2 - x1, y1));
                e.Graphics.FillRectangle(br, new Rectangle(x1, y2, x2 - x1, this.Height - y2));
            }

            using (Pen pen = new Pen(Color.Red, 2))
            {
                e.Graphics.DrawRectangle(pen, rect);
            }
        }
    }



Let me know if this helps or not.
Aland Li


Please mark the replies as answers if they help and unmark if they don't. This can be beneficial to other community members reading the thread.
Aland Li  Friday, September 25, 2009 6:47 AM
I've tried resizing the form to some size instead of using Maximize with FormBorderStyle set to "true" and the rectangle is smooth!
I'll guess that you use the BackgroundImage property to display the image. That's is going to get slow if the image needs to be rescaled to fit the form. Override the OnResizeEnd() method of the form and re-create the image, make it exactly as large as ClientSize. Also make sure it is in the 32bppPArgb format, it is faster by a factor of 10 on most video hardware.

Hans Passant.
  • Marked As Answer byfarooqaaa Sunday, September 27, 2009 12:18 PM
  •  
nobugz  Friday, September 25, 2009 9:37 AM
Thanks alot! That worked for me!
farooqaaa  Sunday, September 27, 2009 12:20 PM

You can use google to search for other answers

Custom Search

More Threads

• How best to mimic One Note's tabbed notebook sections and pages?
• How to Use .Net Windows Applicaion in Internet Explorer
• run method at exact time
• how to run "Notepad" or "Microsoft word" in VB.net 2003
• Displaying in-memory images on WebBrower control
• How to capture MouseHover repeatedly?
• Mdi parent and child form width
• checkbox problem
• Find width and length of an image w/0 loading it
• clear combobox issue