Winforms:如何在透明表单上获取透明控件的鼠标事件

时间:2015-09-04 03:24:22

标签: c# .net winforms transparency

我有一个透明的表单,它在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);
   }
}

这样可以创建我正在寻找的精确效果,因为在透明表单内部有一个带有实心不透明矩形边框的控件,您可以通过控件和窗体看到桌面(请参见左下图)。 / p>

enter image description here

问题是控件的透明区域没有收到任何鼠标事件。实际上,它基本上不存在。例如,当鼠标越过控件的红色矩形边框时,触发鼠标悬停,鼠标输入和鼠标离开事件,并将光标更改为您为控件设置为this.Cursor的任何内容。有一次,鼠标位于控件的透明部分,这些都不会触发。

我如何按照控件的外观保持现状,但仍然在透明区域接收鼠标事件。特别是我希望收到鼠标悬停并且控制Cursor值。请注意,如果我将控件的BackColor设为Color.Transparent以外的任何内容,则鼠标事件可以正常工作。

谢谢!

更新

根据Hans评论,我想补充一点,我们已经实现了上述功能并且它通常有效(即透明区域确实响应鼠标事件)。出现这个问题的原因是因为我最近使用所有Windows 8.1更新和最新的ATI图形驱动程序重建了我的机器,之后上述设置不再有效(控件上的透明区域不再接收任何鼠标事件和所有意图并且目的不是控制的一部分)在我的同事的机器上,它几乎总是有效,虽然我们偶尔会注意到它不起作用,但我们永远不能始终如一地重现这个问题。

我的假设是我们做错了导致透明区域不响应鼠标事件。然而,基于Hans的评论,似乎上述代码永远不会起作用,并且它起作用的唯一原因是因为Aero中的错误。

透明度密钥的确切颜色为rgb(255, 128, 0)。此外,我们注意到放在透明表格上的任何标签控件看起来都很糟糕(根据Han的评论)。

更新2

根据Han关于Aero透明度错误的其他评论,我有以下更新的问题。

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

    下面的Reza提供的答案在我的一些电脑上为我工作。但是,我的主桌面继续顽固地拒绝合作。即使使用相同版本的Windows和.NET在计算机之间复制精确项目,也存在问题。它产生的问题是透明区域不会触发鼠标事件,也不会被视为控制的一部分。

    此外,我注意到Reza注意到同样的事情,即某些TransparencyKey颜色变得平坦无效。虽然我不知道任何有关该bug的细节,但我不得不同意汉斯的说法,即WinForms的透明度存在漏洞,如果有人从头开始,我会选择WPF路由,以避免任何可能的未来头痛。

    最后,我们最终根据Hans的一些答案实现了一项工作,这些答案需要使用计时器来检查鼠标位置并嵌套两个表单(一个具有不透明度设置)以便能够管理鼠标光标。这个解决方案适用于我们所有的系统,并且希望能够持续到我们转移到WPF。我接受了Reza的答案,因为它似乎适用于大多数地方,但要注意它可能对你不起作用,并且没有任何押韵或理由。

    有关我们实施的两种解决方法的详细信息,请参阅Hans的以下问题和解答。

    MouseHover and MouseLeave Events controlling

    How can I add transparency to a c# form while keeping controls visible?

2 个答案:

答案 0 :(得分:3)

重要

考虑将表单的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;
        }
    }
}

对于鼠标进入时的鼠标事件和渲染边框,以下是我在.Net 4.5上使用Windows 8.1所做的示例:

创建Form并将我们使用上面代码创建的TransparentControl放在其上,然后处理MouseEnterMouseLeave以及Paint事件并绘制当鼠标处于控制状态并处理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");
}

<强>截图

enter image description here

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

重要提示

如果您使用与表单透明度键相同的颜色绘制边框,则不会显示边框。

答案 1 :(得分:1)

我认为将鼠标光标移到该覆盖框的中间并随鼠标光标和覆盖框一起移动以使其看起来像是鼠标光标是可以的。

enter image description here

喜欢这张照片