繁体   English   中英

Winforms:如何为透明窗体上的透明控件获取鼠标事件

[英]Winforms: How to get Mouse Events for Transparent Control on a Transparent Form

我有一个透明的表单,它覆盖在 ac# .NET winforms 应用程序中的桌面。 通过将BackColor设置为亮橙色,然后将TransparencyKey设置为相同的亮橙色来实现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以外的任何Color.Transparent则鼠标事件可以正常工作。

谢谢!

更新

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

我的假设是我们做错了什么导致透明区域不响应鼠标事件。 然而,根据 Hans 的评论,似乎上面的代码永远不会工作,它工作的唯一原因是因为 Aero 中的错误。

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

更新 2

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

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

最终答案(通常有效)

下面 Reza 提供的答案在我的某些计算机上确实对我有用。 然而,我的主桌面继续固执地拒绝合作。 即使在使用相同版本的 windows 和 .NET 的计算机之间复制确切的项目时,问题仍然存在。 出现的问题是透明区域不会触发鼠标事件,也不会被视为控件的一部分。

此外,我还注意到 Reza 注意到的同一件事,即某些透明键颜色平淡不起作用。 虽然我不知道该错误的任何细节,但我不得不同意 Hans 的观点,即 WinForms 上存在与透明度有关的错误,如果有人从头开始,我会走 WPF 路线,以免将来遇到任何可能的麻烦。

最后,我们最终根据 Hans 的一些答案实施了一个变通方法,即需要使用计时器来检查鼠标位置并嵌套两个表单(一个设置了不透明度)才能管理鼠标光标。 该解决方案适用于我们所有的系统,并有望在我们转向 WPF 之前一直有效。 我接受了 Reza 的回答,因为它似乎在大多数地方都有效,但请注意,它可能对您不起作用,并且没有韵律或原因。

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

MouseHover 和 MouseLeave 事件控制

如何在保持控件可见的同时向 ac# 表单添加透明度?

重要的

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

我看到的奇怪的事情是,该方法不适用于例如洋红色,但适用于红色和蓝色。


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

透明控制码

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;
        }
    }
}

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

创建一个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");
}

截屏

在此处输入图片说明

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

重要的提示

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

我认为鼠标光标可以进入覆盖框的中间并随着鼠标光标和覆盖框移动,使其看起来像一个鼠标光标。

在此处输入图片说明

喜欢这张图

当我在透明窗体上使用图片框控件并在控件上使用 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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM