我在选项卡中有我的用户控件。用户控件内的文本模糊。请在
下找到用户控件绘制事件的代码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控件
修改
下面有模糊和正确的图像答案 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(虽然我更喜欢Lockbits
到unsafe
),但正如我所说,这个不是你想要的......
<强>更新强>
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.Clear
或Color.Transparent
无关。
我认为,由于您要覆盖OnLayout
,因此您打算将此控件与其Anchor或Dock属性集一起使用。所以我将Dock属性设置为填写我的测试项目,然后重新运行应用程序。我再次无法重现这个问题。但是,我注意到,当快速调整容器形状的大小时,我可以生产&#34;撕裂&#34;效果或其他视觉文物。例如,当我使表单非常小时,我会看到多次绘制的文本:
这是由表格快速调整大小引起的竞争状况。客户端矩形的尺寸变化太快,并且表格的新曝光区域未被擦除。让我看看我是否可以解释实际发生的事情。
DrawString
将文本绘制到其中。图像太窄,无法将整个字符串放在一条线上,因此它包裹了&#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
。