Highlighting Winforms shortcuts above a button with a custom drawing

So I have this little app with a button and a shortcut. The button has custom OnPaint methods to make it unique. Not currently on the label. However, the label seems to be drawing inside the button for no apparent reason. Look at this:

The problem

For clarity, I've turned off the display of the fill rectangle as it mostly covers the problem. Here's my button OnPaint code:

    protected override void OnPaint(PaintEventArgs e)
    {
        Graphics g = e.Graphics;
        g.SmoothingMode = SmoothingMode.HighQuality;
        Pen p = new Pen (Color.Black, 2);
        Rectangle fillRect = new Rectangle (e.ClipRectangle.X, e.ClipRectangle.Y, e.ClipRectangle.Width - 2, e.ClipRectangle.Height - 2);
        Brush b;
        if (MouseHovering)
        {
            b = new SolidBrush (Color.DarkSlateGray);
        } 
        else
        {
            b = new SolidBrush (Color.Gray);
        }
        //g.FillRectangle (b, fillRect);
        g.DrawRectangle (p, e.ClipRectangle);
        //g.DrawString (Text, new Font ("Arial", 8), new SolidBrush (Color.Black), new Point (4, 4));
    }

      

And here is the code that creates the label and button in the main form class:

label = new Label ();
label.Text = "Hello World";
label.Top = 15;
label.Left = 180;
label.AutoSize = true;
Controls.Add (label);
CButton b = new CButton ();
b.Text = "Click me for a new sentence";
b.AutoSize = true;
b.Top = 10; b.Left = 10;
Controls.Add (b);

      

The above is called in the constructor. And then when the button is clicked, the caption text is set like this:

label.Text = Specifier + " " + Verb + " a " + CommonNoun;

      

So what's going on here and how do I fix it? If you need any other code to understand the problem, feel free to ask.

+3


source to share


1 answer


Some things are missing. g.Clear(BackColor);

will clear the contents of the buffer on which the Graphics is drawn.

protected override void OnPaint(PaintEventArgs e)
    {
        Graphics g = e.Graphics;
        g.Clear(BackColor);
        g.SmoothingMode = SmoothingMode.HighQuality;
        Pen p = new Pen (Color.Black, 2);
        Rectangle fillRect = new Rectangle (e.ClipRectangle.X, e.ClipRectangle.Y, e.ClipRectangle.Width - 2, e.ClipRectangle.Height - 2);
        Brush b;
        if (MouseHovering)
        {
            b = new SolidBrush (Color.DarkSlateGray);
        } 
        else
        {
            b = new SolidBrush (Color.Gray);
        }
        //g.FillRectangle (b, fillRect);
        g.DrawRectangle (p, e.ClipRectangle);
        //g.DrawString (Text, new Font ("Arial", 8), new SolidBrush (Color.Black), new Point (4, 4));
        b.Dispose();   //ADD THIS
        p.Dispose();   //ADD THIS TOO
    }

      

Also remember that it is very important to get rid of any GDI resources you are using. They might be .NET constructs, but they are really unmanaged objects in the background. Eliminating them properly will prevent memory leaks and hard-to-find crashes.

Also, you don't have to use the clip rectangle, use the actual borders of the control.



The best option is to use them when using operators:

protected override void OnPaint(PaintEventArgs e)
    {
        Graphics g = e.Graphics;
        g.SmoothingMode = SmoothingMode.HighQuality;

        Color fillColor = MouseHovering ? Color.DarkSlateGray : Color.Gray;

        using (Pen p = new Pen(Color.Black, 2))
        using (Brush b = new SolidBrush(fillColor))
        {
            Rectangle fillRect = new Rectangle (0, 0, this.Width, this.Height);

            g.DrawRectangle (p, e.ClipRectangle);
        }
    }

      

Using the operator using

has the added benefit of having an exception in its use, the objects will still be removed correctly. Another option is to wrap them in try..catch..finally

, but if you don't have to do something about the exception, this is much cleaner.

+1


source







All Articles