我正在尝试在我的控件的 OnPaint() 方法中使用(这可能已经是我的问题)e.Graphics.CopyFromScreen() 来准备一个背景,我可以在其上绘制控件的内容。目标是具有圆角和其他特定功能的工具提示,以替换默认的 Windows 工具提示。
理想情况下,工具提示可以抗锯齿并混合到背景中,但是在紧要关头,我可以容忍锯齿边界。这也可能是必要的,因为控件通常会用 OpenGL 覆盖覆盖控件,并且整个混合过程可能最终成为一场噩梦。
我创建了一个自定义用户控件,这是一个持久实例,它依赖于我的应用程序的主窗体,重写 OnPaint 和 OnPaintBackground 方法。然而,透明度的应用具有挑战性。据我了解,传递给 paint 方法的图形对象从当前 VisibleClipBounds 的副本开始,通常第一步是使用纯色清除控件并开始绘制主要功能。我的第一个想法是绕过填充并开始在捕获的背景上绘图。对于第一次重绘,这工作正常,但随后的重绘会保留之前的内容,而不是重新捕获背景。我希望 CopyFromScreen 能够专门从其捕获中删除当前绘图控件,以便从干净的基础开始,但事实并非如此,它会捕获新位置的矩形,包括先前位置的图像(如果它在边界内)。
其他解决方案及其排列,例如
SetStyle(ControlStyles.SupportsTransparentBackColor, True)
Me.BackColor = Color.Transparent
e.Graphics.Clear(Color.FromArgb(0,0,0,0))
迄今为止没有产生适当的结果。
我从使用透明键颜色的透明表单开始。这适用于锯齿,但使用窗体作为工具提示似乎过多,并导致烦人的伪影(其中一些可以克服),例如任务栏按钮的临时存在、基础表单的焦点丢失以及宿主窗体标题栏颜色中的后续视觉反馈。控件的重量要轻得多,但我正在努力使其与形式一样工作。
在这一点上,我只是问如何实现预期的结果,以及CopyFromScreen是否是该解决方案的一部分。
阅读的文本很多 - 但解决透明度以实现自定义形状的表单/控件......Control.Region 可以做同样的事情:
[DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn")]
private static extern IntPtr CreateRoundRectRgn
(
int nLeftRect, // x-coordinate of upper-left corner
int nTopRect, // y-coordinate of upper-left corner
int nRightRect, // x-coordinate of lower-right corner
int nBottomRect, // y-coordinate of lower-right corner
int nWidthEllipse, // height of ellipse
int nHeightEllipse // width of ellipse
);
private void CreateRegion()
{
this.Region = System.Drawing.Region.FromHrgn(CreateRoundRectRgn(0, 0, Width, Height, 40, 40));
}
如果您的控件设置为顶级窗口,并且您在 Windows 7 或 8 上运行它,请检查 DwmEnableBlurBehindWindow。在参数结构中,我将 enable 设置为 true,并为模糊创建一个 1x1 像素的区域。将 BackColor 和 TransparencyKey 设置为 Black 后,这为我提供了一个完全透明的窗口(带有鼠标直通),我可以将 32 位图像绘制为具有完全 alpha 透明度(使用 Graphics.FromHwnd)。此方法的一个好处是,如果窗口移动或背景更改,Windows DWM 将完成所有工作 - 我不必更新任何内容。