【问题标题】:Winforms: How to get Mouse Events for Transparent Control on a Transparent FormWinforms:如何为透明表单上的透明控件获取鼠标事件
【发布时间】: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 透明度错误的补充评论,我有以下更新的问题。

  1. 是否有任何关于此错误的信息可以解释错误是什么?
  2. 控件透明区域的预期行为(假设没有错误)是什么?鼠标事件(例如,鼠标悬停)是否应该在透明区域上工作?

最终答案(通常有效)

下面 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


【解决方案1】:

重要

考虑将表单的BackgroundColor 设置为红色,将TransparencyKey 设置为红色,将透明控件的BackGroundColor 设置为透明,这样就可以了!

我看到的奇怪之处是,这种方法不适用于例如 Magenta,但适用于 Red 和 Blue。


我认为您应该以这种方式创建透明控件:

透明控制代码

public class TransparentControl : Control
{
    public TransparentControl()
    {
        this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
    }

    private const int WS_EX_TRANSPARENT = 0x20;
    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;
            cp.ExStyle = cp.ExStyle | WS_EX_TRANSPARENT;
            return cp;
        }
    }
}

而对于鼠标进入时的鼠标事件和渲染边框,这里是我做的示例 Using .Net 4.5 On Windows 8.1:

创建一个Form 并在其上放置我们使用上述代码创建的TransparentControl,然后处理MouseEnterMouseLeavePaint 事件并在鼠标处于控制状态时绘制边框并处理Click 事件并显示消息。

表单代码

private bool drawBorder;
private void transparentControl1_MouseLeave(object sender, EventArgs e)
{
    drawBorder = false;
    transparentControl1.Invalidate();
}

private void transparentControl1_MouseEnter(object sender, EventArgs e)
{
    drawBorder = true;
    transparentControl1.Invalidate();
}

private void transparentControl1_Paint(object sender, PaintEventArgs e)
{
    if(drawBorder)
    {
        using (var pen = new Pen(this.ForeColor, 5))
        {
            e.Graphics.DrawRectangle(pen, 0, 0, this.transparentControl1.Width - 1, this.transparentControl1.Height - 1);
        }
    }
}

private void transparentControl1_Click(object sender, EventArgs e)
{
    MessageBox.Show("Clicked");
}

截图

鼠标光标位于控件的区域,因此黑色边框已被绘制。

重要提示

如果你绘制的边框与表单的透明键颜色相同,边框将不会显示。

【讨论】:

    【解决方案2】:

    我认为鼠标光标可以进入该叠加框的中间并随着鼠标光标和叠加框移动以使其看起来像鼠标光标。

    喜欢这张照片

    【讨论】:

    • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
    • @Nikaido 这不是链接,而是图片...请查看我的编辑
    【解决方案3】:

    当我在透明表单上使用图片框控件并在控件上使用 mouseclick 事件来触发代码时,我遇到了类似的问题。有时会捕获鼠标单击,有时则不会。除了用作表单背景的颜色外,没有其他图案。红色效果很好,但许多其他颜色却不行。即使是黑色也不能始终如一地工作。我发现当 form.backcolor 和 form.transparencykey 设置为这种颜色时,几乎是黑色的颜色可以正常工作。根据此经验和其他经验,VB Studio 中出现了一个错误以及处理透明度的方式。

    Form1.BackColor = Color.FromArgb(64, 0, 0) ' a color that works with transparency and allows picturebox to be clicked

    【讨论】:

      猜你喜欢
      • 2013-01-04
      • 2011-12-20
      • 1970-01-01
      • 2022-03-19
      • 1970-01-01
      • 1970-01-01
      • 2013-03-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多