【发布时间】:2015-11-30 02:40:20
【问题描述】:
我有一个透明的表单,它覆盖在 c# .NET winforms 应用程序中的桌面上。通过将BackColor 设置为亮橙色,然后将TransparencyKey 设置为相同的亮橙色来实现透明度。
到目前为止,这很有效,它创建了一个透明的表单。然后,我想在透明表单上创建一个控件,该控件在桌面上的项目周围绘制一个矩形。所以基本上你可以想到一个带有矩形边框的透明按钮。为了实现这一点,我目前扩展了 Control 并在父表单中设置了这样的控件,它也是透明的:
public class CustomControl : Control
{
public CustomControl(Size size, Point point)
{
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
this.BackColor = Color.Transparent;
this.Size = size;
this.Location = point;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Pen pen = new Pen(Color.Red, 2f);
e.Graphics.DrawRectangle(pen, this.ClientRectangle);
}
}
这会产生我正在寻找的确切效果,因为在透明表单内有一个带有实心不透明矩形边框的控件,您可以通过控件和表单看到桌面(见左下图)。
问题是控件的透明区域没有接收到任何鼠标事件。事实上,它基本上是不存在的。例如,当您的鼠标越过触发鼠标悬停、鼠标进入和鼠标离开事件的控件的红色矩形边框并将光标更改为您为控件设置的this.Cursor 时。有一次,鼠标位于控件的透明部分,这些都不会触发。
关于控件的外观,我怎样才能保持它们现在的样子,但仍然在透明区域接收鼠标事件。特别是我想接收鼠标悬停并让控件Cursor 值得到尊重。请注意,如果我将控件的 BackColor 设为 Color.Transparent 以外的任何其他值,则鼠标事件可以正常工作。
谢谢!
更新
根据 Hans 的评论,我想补充一点,我们已经实现了上述内容并且它通常可以工作(即透明区域确实响应鼠标事件)。出现此问题的原因是因为我最近使用所有 Windows 8.1 更新和最新的 ATI 图形驱动程序重建了我的机器,之后上述设置不再有效(控件上的透明区域不再接收任何鼠标事件和所有意图和目的不是控制的一部分)在我同事的机器上,它几乎总是可以工作,尽管我们偶尔会注意到它不起作用,但我们永远无法始终如一地重现该问题。
我的假设是我们做错了什么导致透明区域不响应鼠标事件。然而,根据 Hans 的评论,上面的代码似乎永远不会工作,它工作的唯一原因是 Aero 中的一个错误。
我们的透明度键的确切颜色是rgb(255, 128, 0)。此外,我们确实注意到放置在透明表单上的任何标签控件看起来都很糟糕(根据 Han 的评论)。
更新 2
根据 Han 对 Aero 透明度错误的补充评论,我有以下更新的问题。
- 是否有任何关于此错误的信息可以解释错误是什么?
- 控件透明区域的预期行为(假设没有错误)是什么?鼠标事件(例如,鼠标悬停)是否应该在透明区域上工作?
最终答案(通常有效)
下面 Reza 提供的答案在我的某些计算机上确实对我有用。但是,我的主桌面继续顽固地拒绝合作。即使在使用相同版本的 windows 和 .NET 的计算机之间复制确切的项目时,问题仍然存在。出现的问题是透明区域不会触发鼠标事件,也不会被视为控件的一部分。
此外,我还注意到 Reza 注意到的同一件事,那就是某些 TransparencyKey 颜色完全不起作用。虽然我不知道该错误的任何细节,但我必须同意 Hans 的观点,即 WinForms 上存在与透明度有关的错误,如果有人从头开始,我会走 WPF 路线,为自己节省任何可能的未来头痛。
最后,我们最终根据 Hans 的一些答案实施了一项工作,即需要使用计时器检查鼠标位置并嵌套两个表单(一个设置了不透明度)才能管理鼠标光标。该解决方案已在我们所有的系统上运行,并有望持续到我们转移到 WPF 之前。我接受了 Reza 的回答,因为它似乎在大多数地方都有效,但请注意它可能对您不起作用,并且没有押韵或理由说明原因。
有关我们实施的两种解决方法的详细信息,请参阅 Hans 的以下问题和解答。
MouseHover and MouseLeave Events controlling
How can I add transparency to a c# form while keeping controls visible?
【问题讨论】:
-
看看这个 SO 帖子:stackoverflow.com/questions/14432230/…。 Hans Passant 建议每 50 毫秒检查一次鼠标指针是否在边界内。
-
感谢您的回复。我实际上实现了 Hans 解决方案并且它确实有效,尽管我无法使用此方法为控件正确设置光标,因为透明区域没有被视为控件的一部分。希望我可能遗漏了一些更明显的东西。
-
使用
SetWindowsHookEx添加一个全局鼠标监听器。然后监听 WM_MOUSE 消息。 -
嗯,当您选择 Orange 作为 TransparencyKey 时,它实际上工作得很好。 Aero 中的一个错误,他们无法再修复。你真的试过这个吗?可能不是,你还没有见过大象。当您的表单位于另一个蓝色窗口的顶部时,该文本将看起来非常糟糕。抗锯齿像素完全错误。
-
@HansPassant 我用您的评论让我意识到非常相关的一些新信息更新了这个问题。最重要的是,我们已经实现了这个并且它确实可以工作,但是在最近重建我的桌面(更新所有 Windows 更新并更新我的图形驱动程序)之后,它不再工作了。此外,我们确实注意到透明表单上的标签看起来很糟糕(这不是一个大问题,因为我们不需要标签)。也许我们的实现从未想过工作,但由于您提到的错误而确实有效。是不是只有透明键为橙色时才会有bug?
标签: c# .net winforms transparency