【问题标题】:Problem with CreateGraphics and drawing stringsCreateGraphics 和绘制字符串的问题
【发布时间】:2010-01-14 22:00:54
【问题描述】:

下面的控件在一个矩形中绘制一个字符串。在鼠标移动时,字符串矩形上有一个命中测试,字符串通过 CreateGraphics 重绘。恼人的问题是文本的绘制方式与 Paint 处理程序中的不同;它似乎偏移了大约 1 个像素,效果就像一个粗体。如何创建与 Paint 处理程序中的图形对象完全相同的图形对象,以便以相同的方式绘制文本?通常,您会在 Paint 事件中使所有内容无效并重新绘制,但我可能有数百个其他绘图项,并且只想绘制字符串。我应该尝试在 Paint 事件之外进行任何绘图还是这是一个错误?

示例控件:

using System;
using System.Drawing;
using System.Windows.Forms;

namespace Test.TestModes
{
    public partial class ExampleControl: UserControl
    {
        private const string testString = "0123456789";
        private RectangleF stringRect = new RectangleF(10, 10, 100, 20);

        public ExampleControl()
        {
            InitializeComponent();
        }

        private void ExampleControl_Paint(object sender, PaintEventArgs e)
        {
            Font font = new Font("Arial", 12, FontStyle.Regular);

            e.Graphics.DrawString(testString, font, Brushes.Black, stringRect);

            font.Dispose();
        }

        private void DrawString(bool hit)
        {
            Font font = new Font("Arial", 12, FontStyle.Regular);

            using(Graphics g = CreateGraphics())
            {
                g.SetClip(ClientRectangle);
                if(hit)
                    g.DrawString(testString, font, Brushes.Red, stringRect);
                else
                    g.DrawString(testString, font, Brushes.Black, stringRect);
            }

            font.Dispose();
        }

        private void ExampleControl_MouseMove(object sender, MouseEventArgs e)
        {
            if(stringRect.Contains(e.Location))
                DrawString(true);
            else
                DrawString(false);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Invalidate();
        }


    }
}

【问题讨论】:

  • 你为什么还要使用 CreateGraphics?在 Pain 事件中完成所有绘画,这就是它的用途。
  • 如何只绘制字符串而不绘制控件的其余部分?
  • 我会首先在 DrawString 方法中调试 PaintEventArgs 的 ClipRectangle 的位置和 ClientRectangle,看看是否一切都匹配...
  • 只需在控件上调用 Invalidate,将要刷新的矩形作为参数。 msdn.microsoft.com/en-us/library/8dtk06x2.aspx
  • -- 然后在 Paint 事件中我是否测试每个绘图元素并且仅在剪辑区域中绘制?

标签: c# winforms


【解决方案1】:

是 CreateGraphics() 调用间接地给您带来麻烦。问题是文本的抗锯齿。正常的绘画周期会先擦除背景,然后再在上面绘制一些东西。在您的情况下不会发生这种情况,您在现有文本之上绘制文本。副作用是每次绘制时用于创建锯齿的像素都会变暗。最终的结果是大胆的外观和明显的锯齿状文本轮廓。

解决方法很简单:在绘制之前从头开始:

    using (Graphics g = CreateGraphics()) {
        g.Clear(this.BackColor);                <=== added
        g.SetClip(ClientRectangle);
        // etc..
    }

您现在还会遇到称为“闪烁”的绘图问题。它可能还没有那么明显,但是当你做更多的绘画时它会。双缓冲可抑制闪烁。 Windows 窗体支持的一项功能,但前提是您使用标准绘图技术。换句话说:没有 CreateGraphics()。

【讨论】:

  • 太棒了,就是这样。我失去了 DoubleBuffered 效果,但是当我这样做时,当我移动鼠标时会出现一些闪烁。 (我在加载事件中添加了 DoubleBuffered = true)。所以我想我永远无法在 Paint 事件之外进行绘制。
  • 好吧,你可以自己双缓冲。使用位图 Graphics.FromImage() 并绘制到该图形上下文中。然后 DrawImage() 结果。不过,只调用 Invalidate() 让常规 Paint() 事件处理程序绘制会更好。
猜你喜欢
  • 1970-01-01
  • 2018-10-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-18
  • 1970-01-01
  • 2014-01-04
  • 2015-07-29
  • 1970-01-01
相关资源
最近更新 更多