2015-09-04 96 views
2

我有一个透明表单,它覆盖了c#.NET winforms应用程序中的桌面。通过将BackColor设置为明亮的橙色,然后将TransparencyKey设置为相同的明亮橙色来完成透明度。Winforms:如何在透明表单上获取透明控件的鼠标事件

到目前为止,这个工作很好,它创建一个透明的形式。然后,我想在透明窗体上创建一个控件,在桌面上的项目周围绘制一个矩形。所以基本上你可以想象一个带有矩形边框的透明按钮。要做到这一点我现在延长控制和设置这样父窗体的内部控制,这也是透明的:

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

这造成我在寻找的效果是有控制用固体透明窗体中的不透明矩形边框,您可以通过控件和窗体看到桌面(请参见左下方的图像)。

enter image description here

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

我该如何保持它们现在的状态与控件的外观相似,但仍然在透明区域接收鼠标事件。特别是我想收到鼠标悬停并有控制Cursor值得尊重。请注意,如果我将控件的BackColor设置为Color.Transparent以外的其他值,则鼠标事件可以正常工作。

谢谢!

更新

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

我的设想是我们做了错误的事情导致透明区域不响应鼠标事件。然而,根据汉斯的评论,上面的代码看起来好像永远不会起作用,而且它工作的唯一原因是由于Aero中的错误。

我们的透明键的确切颜色是rgb(255, 128, 0)。另外,我们注意到,透明窗体上的任何标签控件看起来都很糟糕(根据Han的评论)。

更新2

根据韩寒的关于航空透明度错误,我有以下问题更新额外的评论。

  1. 有没有关于这个bug的任何信息来解释错误是什么?
  2. 控件的透明区域的预期行为(假设没有错误)是什么?鼠标事件(例如鼠标悬停)是否在透明区域上工作?下面

最终的答案(即通常工作)

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

另外,我注意到Reza注意到同样的事情,那就是某些TransparencyKey颜色没有起作用。虽然我不知道这个bug的任何细节,但我不得不同意Hans的观点,即WinForms的透明性存在缺陷,如果有人从头开始,我会去WPF路由并为将来的麻烦保存。

最后,我们根据汉斯的一些答案完成了一项工作,这些答案需要使用计时器来检查鼠标位置并嵌套两个窗体(一个窗体为不透明集)以便能够管理鼠标光标。这个解决方案已经在我们所有的系统上运行过了,并且希望能够继续下去,直到我们转向WPF。我接受了Reza的答案,因为它似乎在大多数地方都有效,但请注意它可能不适用于你,而且为什么没有押韵或理由。

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

MouseHover and MouseLeave Events controlling

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

+0

看看这个SO帖子:http://stackoverflow.com/questions/14432230/transparency-and-mouse-events-winforms。 Hans Passant建议每隔50ms检查鼠标指针是否在边界内。 – Christoph

+1

谢谢你的回应。我实际上实现了汉斯解决方案,它确实工作,虽然我无法使用此方法为控件正确设置游标,因为透明区域未被视为控件的一部分。希望我可能错过了更明显的东西。 – Sarus

+0

使用'SetWindowsHookEx'添加全局鼠标侦听器。然后监听WM_MOUSE消息。 – Loathing

回答

2

重要

请考虑设置形式的BackgroundColor以红色和TransparencyKey以红色和透明控制的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; 
     } 
    } 
} 

而对于鼠标事件和渲染边框当鼠标进入,这里是我做过的样品使用.Net 4.5Windows 8.1

创建一个Form并将我们使用上面的代码创建的TransparentControl放在上面,然后处理MouseEnterMouseLeaveMouseLeavePaint事件并在鼠标处于控制范围内时绘制边框并处理事件并显示消息。

表单代码

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

鼠标光标是在控制的区域,这样的黑色边框被画。

重要提示

如果绘制边框的颜色一样form'a透明按键,边框将不显示。

+0

谢谢你的帖子。在我的情况下,我正在绘制带边框的控件来启动(所以不需要drawBorder逻辑)。但是,鼠标事件仅在边框本身上触发,而不是控件的透明部分。例如,如果将鼠标悬停在文件夹图标上,则不会触发MouseHover事件,但如果将鼠标悬停在边框上,则会触发MouseHover事件。你的样品是否有同样的问题?我试图用你的逻辑,但仍然遇到了同样的问题。 – Sarus

+0

你能够整体分享你的测试吗?我似乎无法弄清楚我们的两个应用程序可能有什么区别。 – Sarus

+0

谢谢你的提议。我给你发了封邮件。 – Sarus