Graphics.Clear(Color.Transparent)在制表符控件

时间:2016-05-30 12:34:25

标签: c# winforms graphics gdi+

我在选项卡中有我的用户控件。用户控件内的文本模糊。请在

下找到用户控件绘制事件的代码
protected override void OnPaint(PaintEventArgs e)
{
     //Avoid redrawing the control unnecessarily
     if(redraw)
     {
         using (Graphics g = Graphics.FromImage(buffer))
         {
                g.Clear(Color.Transparent);
                draw(g, ClientRectangle);
         }
     }
     e.Graphics.DrawImage(buffer, Point.Empty);
}

如果我将控件放在VS工具箱中的Tab控件中,我注意到以下事项。

1)用户控件中绘制的文字模糊

2)油漆事件触发三次。由于条件重绘,绘图逻辑将执行一次,现有缓冲区将在第二次和第三次绘制

3)如果我使用g.Clear(Color.White),文字看起来不错

g.Clear行应该清除Bitmap(缓冲区)并用指定的颜色填充它。它还清除图形对象的状态。如果我使用透明以外的任何颜色,则文字不会模糊。

g.Clear(Color.White)和g.Clear(Color.Transparent)之间是否有任何显着差异?

注意:Color.White只是一个例子。任何命名颜色都可以解决问题。也只能使用Tab控件

修改

下面有模糊和正确的图像

Blurry Text

Normal image

2 个答案:

答案 0 :(得分:2)

除了如何解决问题的建议外,让我纠正两个错误观念。

  •   

    Color.Transparent本质上是一个无操作 - 它绝对没有什么

使用Color.Transparent填充/清除所有像素将使透明黑色(0,0,0,0)

与sombody的评论相反,这是并非一无所有;当一个人真的想要在透明画布上画画时,它是有用的和正常的开始。

由于你的结果看起来不对,你最好用你真正想要的颜色清除画布。如果您希望显示类似TabPage的副本,您应该首先填写该页面的BackColor

g.Clear(tapPage1.BackColor);

另一种说法,这次你是:

  •   

    使用g.Clear(Color.Transparent)用黑色填充位图。

好吧,正如我所说,它确实填充了透明黑色(0,0,0,0)。它没有填充真实黑色(255,0,0,0)。

所有成像软件均不支持透明度。一个特别糟糕的程序是(强大的) IrfanView ,到今天它将显示任何透明度为黑色。 Paint .Net 将显示'它是正确的'意思是通过在棋盘图案下面用透明像素照亮槽来实现它。

制作图像'只是'透明(alpha=0)而不清除RBG个频道,您可以使用例行like this(虽然我更喜欢Lockbitsunsafe),但正如我所说,这个不是你想要的......

<强>更新

g.Clear(Color.Transparent);

实际上可以使画布透明;这是在位图 ..

上使用它时会发生的情况

..或者在控件上使用它时会显示父颜色。如果你在没有父母的表格上使用它,它会使它看起来是黑色的。

答案 1 :(得分:1)

在什么宇宙中,#34;清除&#34;使用透明颜色?

Color.Transparent是......透明的。定义为没有颜色。如果你填充透明的颜色,你什么都不填。空虚。透明度。

如果你用透明颜色填充其上有文字的东西,它将没有任何效果,文字将保留在那里。然后,如果你在它上面绘制相同的文本,你会看到模糊(至少,假设文本是消除锯齿的;如果不是,那么什么都不会改变)。

Color.Transparent以外的任何颜色都可以清除该区域,因为它们是不透明的颜色。这意味着它们与透明相反。你无法透视它们,所以它们实际上掩盖了它们背后的东西。

您也非常努力地优化代码。调用Paint事件处理程序时,需要绘制。操作系统已经为您优化了这一点。所以if (redraw)检查既不必要,也不是一个好主意。只需填写背景颜色,然后在其上绘制图像或文字。

更新:我被指向可能会重现问题的代码here。就像Moonlight Sheng一样,我无法用该代码重现所描述的问题。

这并不奇怪。在链接代码中,由于两个原因,对g.Clear的调用完全是多余的。首先,正如我已经解释的那样,用Color.Transparent清算本质上是一种无操作 - 它绝对没有任何作用。其次,紧接着的线用实心白色笔刷填充整个图像矩形。这有助于&#34;清除&#34;绘图表面,使它全白。你可以用g.Clear(Color.White)完成同样的事情。然后在该白色背景上绘制文本,最后将图像绘制到控件上。这非常有效,因为从来没有任何&#34;透明&#34;区域。无论何时在控件上绘制图像,它都会覆盖(因此擦除)之前的所有内容。绝对没有模糊。因此,这与使用Graphics.ClearColor.Transparent无关。

我认为,由于您要覆盖OnLayout,因此您打算将此控件与其Anchor或Dock属性集一起使用。所以我将Dock属性设置为填写我的测试项目,然后重新运行应用程序。我再次无法重现这个问题。但是,我注意到,当快速调整容器形状的大小时,我可以生产&#34;撕裂&#34;效果或其他视觉文物。例如,当我使表单非常小时,我会看到多次绘制的文本:

这是由表格快速调整大小引起的竞争状况。客户端矩形的尺寸变化太快,并且表格的新曝光区域未被擦除。让我看看我是否可以解释实际发生的事情。

  • 当表单(和控件)更改为 X 大小时,您将销毁旧缓冲区图像并创建一个大小为 X 的新缓冲区图像。然后调用DrawString将文本绘制到其中。图像太窄,无法将整个字符串放在一条线上,因此它包裹了&#34; 100&#34;到第二行。然后将图像绘制到表格上,一切看起来都很好。
  • 然后表单(和控件)更改为 Y 大小。因此,您再次销毁旧缓冲区图像并创建大小为 Y 的新缓冲区图像。这一次,宽度增加了,因此在绘制文本时,所有内容都适合一行。然后将图像绘制到表格上。
  • 哦,等等。尺寸 Y 比尺寸 X 宽,但也更短(不太高)。因此,当您将新缓冲区绘制到表单时,它不会导致先前区域被擦除。这就是为什么你看到旧的&#34; 100&#34;,包裹在第二行,仍然可见。

这很难解释,除非你已经知道绘画是如何运作的,否则我想更难理解。

重要的是,有一个简单的解决方案:将表单的ResizeRedraw属性设置为true,确保每次调整表单时都会引发Paint事件。在控件的OnLayout事件处理程序方法中强制重绘也可以(this.Invalidate()),如下所示:

public partial class MyControl : UserControl
{
   Image buffer;
   public MyControl()
   {
      InitializeComponent();
   }

   protected override void OnLayout(LayoutEventArgs e)
   {
      if (buffer != null)
      {
         buffer.Dispose();
         buffer = null;
      }
      base.OnLayout(e);

      this.Invalidate();  // force a repaint after the layout has changed
   }

   protected override void OnPaint(PaintEventArgs e)
   {
      if (buffer == null)
      {
         buffer = new Bitmap(ClientRectangle.Width, ClientRectangle.Height);

         using (Graphics g = Graphics.FromImage(buffer))
         {
            //g.Clear(Color.Transparent);  // pointless
            g.FillRectangle(Brushes.White, ClientRectangle);
            using (Font f = new System.Drawing.Font("Segoe UI", 12, FontStyle.Regular))
            {
               g.DrawString("Simple text 100", f, Brushes.Black, ClientRectangle);
            }
         }
      }
      e.Graphics.DrawImage(buffer, ClientRectangle);
      base.OnPaint(e);
   }
}

无论如何,这不是声称的错误,而只是误解了绘画子系统在Windows中的工作原理。

顺便提一下,如果您删除对FillRectangle的呼叫(用纯白色填充控件的客户区),您会看到最初描述的模糊文本效果。这是出于我已经说明的确切原因:文本是消除锯齿的,并且在消除锯齿的文本之上绘制抗锯齿文本会产生模糊的&#34;影响。你无法以任何合理的方式解决这个问题。绝对必须在纯色背景上绘制消除锯齿的文字;它cannot be drawn on a transparent background。您需要填写表格的背景颜色。默认情况下,即SystemColors.Control