加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

vb.net – 创建透明控件的一般解决方案是什么?

发布时间:2020-12-17 00:11:13 所属栏目:大数据 来源:网络整理
导读:所以现在看了一会儿,我已经阅读了大概20种不同的实现,但还没有看到基于控件的基于框架的通用解决方案来实现真正透明的控件. 这可能过于简单的方法根本不做任何事情,并创建一个永远不会被使用的例程(InvalidateEx):http://bytes.com/topic/c-sharp/answers/2
所以现在看了一会儿,我已经阅读了大概20种不同的实现,但还没有看到基于控件的基于框架的通用解决方案来实现真正透明的控件.

这可能过于简单的方法根本不做任何事情,并创建一个永远不会被使用的例程(InvalidateEx):http://bytes.com/topic/c-sharp/answers/248836-need-make-user-control-transparent

这似乎暗示了之前的答案:http://www.bobpowell.net/transcontrols.htm

但是使用计时器勾选来执行InvalidateEx方法.

这似乎是放弃了多层控件并处理单个分层面板上的所有绘图,同时掩盖了标签对象如何实现自己的透明度:http://www.codeproject.com/Articles/25048/How-to-Use-Transparent-Images-and-Labels-in-Window

这是一种完全基于非框架的方法:http://www.codeproject.com/Articles/30135/General-solution-for-transparent-controls

这个答案中接受的解决方案根本不适用于我:Transparent Control on Transparent control?

我得到的控件是一般的纯色(白色),上面绘有透明图像.

所以,我从我自己的实现开始.

我宁愿不依赖于自下而上的GDI绘图,即以最父形式执行所有绘图,我宁愿不预先渲染到透明位图,我宁愿不从Forms.Control以外的东西继承这是为了缩短透明度而采取一些巧妙的技巧.我真的想深入了解如何在完全透明支持的控制界面上绘图.显然,标签控件本身内部有一个完整的实现,它是如何工作的?

从逻辑上讲,透明控件不能依赖于简单的1位剪辑区域,并且需要保持大部分完整.需要正确处理多层控件,即正确的绘图顺序等,而不会导致无限循环.

第一个也是最常见的建议是这样的:

SetStyle(ControlStyles.SupportsTransparentBackColor,True)
Me.BackColor = Color.Transparent

我理解的第一行是同义词

Protected Overrides ReadOnly Property CreateParams As System.Windows.Forms.CreateParams
    Get
        Dim result As System.Windows.Forms.CreateParams = MyBase.CreateParams
        result.ExStyle = result.ExStyle Or WindowsMessages.WS_EX_TRANSPARENT
        Return result
    End Get
End Property

根据继承的类,具有非常不同的行为.在Forms.Control的情况下,OnPaintBackground选择使用父控件的背景颜色清除剪辑矩形.不太聪明.

覆盖和删除基本的OnPaintBackground调用会导致控件保持“脏”状态,从未覆盖它下面的内容.使用透明颜色(乐观方法)清除会产生一个黑色透明像素区域,并使控件显示为完全黑色.

从逻辑上讲,这是有道理的,为了提高效率而进行的基础控制不会重新划分他们预期此控制的区域.然后表单中的那个区域永远不会更新,并保留表单存在之前的所有内容.在这上面绘制透明色有点令人困惑,因为它暗示图形缓冲区甚至不包含底层像素,而是用黑色透明的东西替换的实际值,使控件显示为黑色.

第一个挑战似乎是在控件本身重绘时处理,让所有底层控件在该区域重绘(不会自动使控件本身无效以启动堆栈溢出),然后在底层和最新像素上绘制自己.我还没有办法做到这一点.我最接近的是通过挖掘.net代码并找到ButtonRenderer.DrawParentBackground方法.这似乎很有效,尽管快速测试显示重叠组件的z顺序仍未正确处理,底层控件覆盖此控件的顶部.

然后,第二个挑战是在底层控件发生变化时让控件正确地重绘.通过断开挑战1中的自动失效,使得难以通知控件使其自身无效并且不使其父亲无效.

如果有人完全解决了这个问题,请提供代码,如果没有,请提供一些经验,说明如何处理一个或几个问题的部分.

非常感谢.

编辑:

根据WS_EX_TRANSPARENT – What does it actually do?,它似乎是关于WS_EX_TRANSPARENT的假设细节

研究更新:ButtonRenderer.DrawParentBackground实际上仅由Control本身使用,仅在使用Application.EnableVisualStyles()时才强制执行父级的背景绘制.它似乎是一个同义词

InvokePaintBackground(Parent,e.Graphics)

这将重现父控件的所有背景绘制细节.

我创建了所需的一般透明度控件,解决方案是控件及其父级中所有兄弟节点的详细分解,并依赖于InvokePaint()和InvokePaintBackground()方法在OnPaintBackground()方法上准备递归绘图例程.通过连续定义较小的剪辑并与较低的控件相交,此方法可最大限度地减少绘图开销.

>完整的控件包括一种检测和响应兄弟控件’Invalidate方法的方法,有效地绘制透明控件的堆栈,并有效地允许动画底层控件上的完整alpha通道叠加.
>控件可以与子控件和父控件的所有排列交错,同时提供视觉上准确的透明度.
>对照中未考虑命中测试.
>此控件不会过度绘制在绘制事件期间未执行绘制的控件.这是一个很大的限制.
>要使用控件,只需从基础继承并重写OnPaint方法即可执行自定义绘图.只要首先调用对base方法的调用,也可以覆盖OnPaintBackground方法.

最后,如果有人想要包含无效处理的完整代码,请告诉我.如果您有系统绘制组件的解决方案,请告诉我.此外,如果你有一个更微不足道的解决方案,这意味着我浪费了大量的时间,我也不会对收到它感到沮丧!

提供了对OnPaintBackground方法的控件的摘录:

''' <summary>
''' Recursively paint all underlying controls in their relevant regions,stacking drawing operations as necessary.
''' </summary>
''' <param name="pevent"></param>
''' <remarks></remarks>
Protected Overrides Sub OnPaintBackground(pevent As System.Windows.Forms.PaintEventArgs)
    'Store clip and transform for reversion
    Dim initialClip As Region = pevent.Graphics.Clip
    Dim initialTransform As Drawing2D.Matrix = pevent.Graphics.Transform

    'Develop list of underlying controls
    Dim submarinedControls As New List(Of Control)
    For Each Control As Control In m_Siblings
        If Control.Visible AndAlso Above(Control) AndAlso Me.ClientRectangle.IntersectsWith(Control.RelativeClientRectangle(Me)) Then submarinedControls.Add(Control)
    Next

    'Prepare clip for parent draw
    Dim parentClip As System.Drawing.Region = New System.Drawing.Region(initialClip.GetRegionData)
    For Each Control As Control In submarinedControls
        parentClip.Exclude(Control.RelativeClientRectangle(Me))
    Next
    pevent.Graphics.Clip = parentClip

    'Evaluate control relationship to parent,temporarily adjusting transformation for parent redraw. This translation must be relative since the incoming graphics may already have a meaningful transform applied.
    Dim translation As Point = Parent.RelationTo(Me)
    pevent.Graphics.Transform = New Drawing2D.Matrix(1,1,initialTransform.OffsetX + translation.X,initialTransform.OffsetY + translation.Y)

    'Fully draw parent background
    InvokePaintBackground(Parent,pevent)
    InvokePaint(Parent,pevent)

    'Reset transform for sibling drawing
    pevent.Graphics.Transform = initialTransform

    'Develop initial clip of submarined siblings
    Dim siblingClip As System.Drawing.Region = New System.Drawing.Region(initialClip.GetRegionData)
    siblingClip.Exclude(parentClip)

    For Each Control As Control In submarinedControls
        'Define relative position of submarined sibling to self
        translation = Control.RelationTo(Me)

        'Define and apply clip *before* transformation
        Dim intersectionClip As New Region(Control.RelativeClientRectangle(Me))
        intersectionClip.Intersect(siblingClip)
        pevent.Graphics.Clip = intersectionClip

        'Apply transformation
        pevent.Graphics.Transform = New Drawing2D.Matrix(1,initialTransform.OffsetY + translation.Y)

        'Raise sibling control's paint events
        InvokePaintBackground(Control,pevent)
        InvokePaint(Control,pevent)

        'Revert transformation and exclude region
        pevent.Graphics.Transform = initialTransform
        siblingClip.Exclude(intersectionClip)
    Next

    'Revert transform and clip to pre-drawing state
    pevent.Graphics.Transform = initialTransform
    pevent.Graphics.Clip = initialClip
End Sub

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读