Winforms自定义绘制标签覆盖在按钮上的问题

4

我有一个小应用程序,其中包含一个按钮和一个标签。该按钮具有自定义的OnPaint方法,使其看起来独特。但是,标签目前没有。然而,标签似乎出现在按钮内部,原因不明。看看这个:

问题

为了澄清问题,我已禁用了渲染填充矩形,因为它大多数情况下覆盖了问题。这是我的按钮的OnPaint代码:

    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));
    }

以下是在主表单类中创建标签和按钮的代码:

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);

上述代码在构造函数中调用。然后当按钮被按下时,标签文本将被设置为以下内容:
label.Text = Specifier + " " + Verb + " a " + CommonNoun;

那么这里发生了什么?该怎么解决?如果您需要其他代码来理解问题,请不要犹豫,随时联系我们。


3
在你的绘画程序顶部尝试使用g.Clear(BackColor)。同时不要使用剪切矩形,只需使用Rectangle(0, 0, this.Width, this.Height);,确保在结束时处理好你的GDI对象(b.Dispose(),p.Dispose())。 - Ron Beyer
这解决了问题,谢谢! - DavidColson
1
@Ron Beyer 应该将此作为解决方案发布,以便被接受。 - tgolisch
@tgolisch 已完成,之前有点忙,谢谢你的提醒。 - Ron Beyer
1个回答

2

有一些东西丢失了。g.Clear(BackColor); 将清除图形对象正在绘制的缓冲区的内容。

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
    }

请记住,及时处理您正在使用的任何GDI资源非常重要。这些可能是.NET构造,但它们实际上是后台中未经管理的对象。正确处理它们可以避免内存泄漏和难以理解的崩溃。

此外,您不应该使用剪辑矩形,而应使用控件的实际边界。

最佳选择是将它们包装在using语句中:

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语句的好处在于,如果在using语句内部发生异常,对象仍然会被正确处理。另一种选择是将它们包装在try..catch..finally中,但除非需要对异常进行操作,否则using更加简洁。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接