Winforms:如何为透明窗体上的透明控件获取鼠标事件 [英] Winforms: How to get Mouse Events for Transparent Control on a Transparent Form

查看:32
本文介绍了Winforms:如何为透明窗体上的透明控件获取鼠标事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个透明的表单,它覆盖在 c# .NET winforms 应用程序中的桌面上.通过将 BackColor 设置为亮橙色,然后将 TransparencyKey 设置为相同的亮橙色来实现透明度.

到目前为止,这很好用,它创建了一个透明的表单.然后我想在透明窗体上创建一个控件,该控件在桌面上的项目周围绘制一个矩形.所以基本上你可以想到一个带有矩形边框的透明按钮.为了实现这一点,我目前扩展了 Control 并在父窗体中设置了这样的控件,该控件也是透明的:

public class CustomControl : Control{公共自定义控件(大小大小,点点){SetStyle(ControlStyles.SupportsTransparentBackColor, true);this.BackColor = Color.Transparent;this.Size = 大小;this.Location = 点;}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 的以下问答.

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

重要提示

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

I have a transparent form that overlays the desktop in a c# .NET winforms application. The transparency is done by setting the BackColor to bright orange and then setting the TransparencyKey to the same bright orange.

So far this works great and it creates a transparent form. I then want to create a control on the transparent form that draws a rectangle around items on the desktop. So essentially you can think of a transparent button with a rectangular border. To make this happen I currently extend Control and setup the control like this inside of the parent form which is also transparent:

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 creates the exact effect I'm looking for in that there is a control with a solid opaque rectangle border inside a transparent form and you can see the desktop through the control and form (see image below on left side).

The problem is that the transparent area of the control does not receive any mouse events. In fact, it basically doesn't exist. For example, when your mouse goes over the red rectangular border of the control that triggers the Mouse Hover, Mouse Enter, and Mouse Leave events and changes the cursor to whatever you set as this.Cursor for the control. Once, the mouse is in the transparent portion of the control none of these things trigger.

How can I keep things the way they are now in regards to the look of the control but still receive mouse events in the transparent area. In particular I want to receive Mouse Hover and have the controls Cursor value be honored. Note that if I make the BackColor of the control anything other than Color.Transparent then mouse events work fine.

Thank you!

Update

Based on Hans comment I would like to add that we have implemented the above and that it has usually worked (i.e., the transparent area does respond to mouse events). The reason this issue came up is because I recently rebuilt my machine with all the Windows 8.1 updates and latest ATI graphic drivers and after that the above setup no longer works ever (transparent areas on the control no longer receive any mouse events and for all intents and purposes are not part of the control) On my colleague's machine it almost always works although we've occasionally noticed that it won't work but we could never consistently reproduce the issue.

My assumption was that we did something wrong to cause the transparent areas to not respond to mouse events. However, based on Hans' comment, it seems as though the above code should never work and that the only reason it worked was because of a bug in Aero.

The exact color of our transparency key is rgb(255, 128, 0). In addition we did notice that any label controls placed on the transparent form look terrible (per Han's comment).

Update 2

Based on Han's additional comment regarding the Aero transparency bug I have the following updated questions.

  1. Is there any information on this bug somewhere that explains what the bug is?
  2. What is the intended behavior (assume there are no bugs) for transparent areas of a control? Should mouse events (e.g., Mouse Hover) work on the transparent area?

The Final Answer (that usually works)

The answered provided by Reza below did work for me on some of my computers. However, my primary desktop continued to stubbornly refuse to cooperate. Even when copying the exact project between computers using the same version of windows and .NET the problem existed. The issue when it arose was that transparent areas would not trigger mouse events and were not treated as part of the control.

In addition, I noticed the same thing Reza noticed which was that certain TransparencyKey colors flat out did not work. Although I don't know any details of the bug I would have to agree with Hans that there are bugs involved with transparency on WinForms and if anyone is starting from scratch I would go the WPF route and save yourself any possible future headaches.

In the end we ended up implementing a work around based on some of Hans' answers that required using a timer to check the mouse location and nesting two forms (one with opacity set) to be able to manage the mouse cursor. This solution has worked on all our systems and will hopefully hold up until we move over to WPF. I accepted Reza's answer because it seems to work in most places but be aware that it might not work you and there is no rhyme or reason as to why.

For detailed information on the two workaround we implemented please see the following questions and answers by Hans.

MouseHover and MouseLeave Events controlling

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

解决方案

Important

Consider set BackgroundColor of form to Red and TransparencyKey to Red and BackGroundColor of transparent control to Transparent and it will work!

the strange thing that I see is, the approach doesn't work with for example Magenta but works with Red and Blue.


I think you should create your transparent control this way:

Transparent Control Code

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

And for the mouse events and rendering border when the mouse enters, here is the sample I did Using .Net 4.5 On Windows 8.1:

Create a Form and put a TransparentControl that we created using above code, on it, then handle MouseEnter and MouseLeave and Paint events and paint the border when mouse is in control bouds and handle Click event and show a message.

Form Code

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

Screenshot

The mouse cursor is in the control's area so the black border has been painted.

Important Note

If you draw border the same color as form's transparency key, the border will not be shown.

这篇关于Winforms:如何为透明窗体上的透明控件获取鼠标事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆