如何创建一个在其他控件之上工作的透明控件?
我有一个控件(派生自 System.Windows.Forms.Control),它在某些区域需要透明。 我已经通过使用 SetStyle() 实现了这一点:
public TransparentControl()
{
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
this.BackColor = Color.Transparent.
}
现在,如果窗体和透明控件之间没有控件,则此方法有效。 但是,如果透明控件下面恰好有另一个控件(这是此处的用例),则它不起作用。 中间的控件没有绘制,但是下面的表格确实显示出来了。 我可以通过重写 CreateParams 并设置 WS_EX_TRANSPARENT 标志来获得所需的效果,如下所示:
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x20; // WS_EX_TRANSPARENT
return cp;
}
}
这里的问题是它确实减慢了控件的绘制速度。 该控件已经是双缓冲的,因此无需执行任何操作。 性能受到如此严重的影响,以至于令人无法接受。 还有其他人遇到过这个问题吗? 我能找到的所有资源都建议使用方法 #1,但同样,这在我的情况下不起作用。
编辑:我应该注意到我确实有一个解决方法。 子(透明)控件可以简单地将自己绘制到父级的 Graphics 对象上,但这确实很丑,而且我根本不喜欢这个解决方案(尽管这可能是我所拥有的全部)。
EDIT2:因此,根据我得到的有关透明度在 .NET 中如何工作的建议,我在包含透明控件的用户控件中实现了 IContainer 接口。 我创建了一个实现 ISite 的类,将子控件添加到 UserControl 的 Components 集合中,Container 属性在调试器中正确排列,但我仍然没有获得透明效果。 有人有什么想法吗?
I have a control (derived from System.Windows.Forms.Control) which needs to be transparent in some areas. I have implemented this by using SetStyle():
public TransparentControl()
{
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
this.BackColor = Color.Transparent.
}
Now, this works if there are no controls between the form and the transparent control. However, if there happens to be another control below the transparent control (which is the use case here), it does not work. The intermediate control is not draw, but the form below does show through. I can get the effect that I need by overriding CreateParams and setting the WS_EX_TRANSPARENT flasg like so:
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x20; // WS_EX_TRANSPARENT
return cp;
}
}
The problem here is that it really slows down the painting of the control. The control is already double buffered, so nothing to do there. The performance hit is so bad that it is unacceptable. Has anyone else encountered this problem? All of the resources that I can find suggest using method #1, but again, that does not work in my case.
EDIT: I should note that I do have a workaround. The child (transparent) controls could simply draw themselves onto the parent's Graphics object, but it is really ungly and I don't like the solution at all (though it may be all I have).
EDIT2: So, following the advice that I got on how transparency works in .NET, I have implemented the IContainer interface in my user control which contains the transparent controls. I have created a class which implements ISite, I add my child controls to the Components collection of the UserControl, the Container property lines up correctly in the debugger, but I still do not get a transparency effect. Does anyone have any ideas?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
这只是我做的一个简单的事情。我发现的唯一问题是,当更新相交控件时它不会更新。
它的工作原理是将当前控件后面/相交的控件绘制为位图,然后将该位图绘制到当前控件。
This is just a simple thing I cooked up.. The only issue I've found is that it doesn't update when the intersecting controls are updated..
It works by drawing a control that's behind/intersects with the current control to a bitmap, then drawing that bitmap to the current control..
DotNet 中的透明控件是通过让透明控件的容器在透明控件的窗口中绘制自身,然后让透明控件绘制自身来实现的。 此过程没有考虑重叠控制的可能性。 因此,您需要使用某种解决方法才能使其正常工作。
在某些情况下,我在复杂嵌套方面取得了成功,但这主要只适用于位图的快速和肮脏的分层,并且它不能解决部分重叠控件的任何问题。
Transparent controls in DotNet are implemented by having the transparent control's container draw itself in the transparent control's window and then having the transparent control draw itself. This process doesn't take into account the possibility of overlapping controls. So you will need to use some sort of work-around to make it work.
In some cases I've had success with complex nesting, but that's mostly only good for quick-and-dirty layering of bitmaps, and it doesn't solve any issues with partially overlapping controls.
我发现下面的修改使事情变得更快一些:
我还认为使用
this.Width
/this.Height
而不是Parent.Width
> /Parent.Height
会更快,但我没有时间修改它。I found out that the modifications below make things a bit faster:
I also think that using
this.Width
/this.Height
instead ofParent.Width
/Parent.Height
would be even faster, but I didn't have time to tinker with it.将兄弟姐妹置于控制之下是可能的,但它很丑。 下面的代码对我来说效果相当好,它扩展了 Ed S.' 中链接中给出的代码。 回答。
可能的陷阱:
DrawToBitmap
是在 .net 2.0 中引入的,因此不要指望它可以与比 .net 2.0 更旧的版本一起工作。 但即便如此,通过向同级控件发送 WM_PRINT 也可能实现类似的操作; AFAIK 这就是 DrawToBitmap 内部所做的事情。这是代码:
Drawing the siblings under the control is possible, but it's ugly. The code below works reasonably well for me, it expands on the code given in the link in Ed S.' answer.
Possible pitfalls:
DrawToBitmap
was introduced with .net 2.0, so don't expect it to work with anything older than that. But even then something like this may be possible by sending WM_PRINT to the sibling control; AFAIK that's what DrawToBitmap does internally.WS_EX_TRANSPARENT
since according to msdn that window style fiddles with the painting order. I haven't got any controls that use this style so I can't tell.Here's the code:
我决定简单地在子控件下手动绘制父控件。 这是一篇好文章。
I decided to simply paint the parent under my child controls manually. Here is a good article.
一些建议(对 VB 代码表示歉意)。
尽量避免绘制背景:
不要调用控件的基本绘制方法:
Some suggestions (apologies for the VB code).
Try to avoid painting the background:
Don't call the controls base paint method:
这确实有效,至少对我来说是这样:
This does the trick, at least it has for me: