6

しばらくこれを調べて、おそらく 20 の異なる実装を読みましたが、真に透過的なコントロールを実装するための、しっかりした、コントロールベース、フレームワークベースの一般的なソリューションをまだ見ていません。

このおそらく単純化されたアプローチはまったく何もせず、決して使用されないルーチン (InvalidateEx) を作成します: http://bytes.com/topic/c-sharp/answers/248836-need-make-user-control-transparent

これは、以前の回答が得ていたものを示唆しているようです: https://web.archive.org/web/20141227200000/http://bobpowell.net/transcontrols.aspx

ただし、タイマーティックを使用して 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

この回答で受け入れられた解決策は、単に私にはうまくいきません:透明なコントロールの透明なコントロール?

私が取得するコントロールは、透明な画像が描かれた一般的な単色 (白) です。

だから、私は自分の実装を開始します。

ボトムアップの 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 オーダーがまだ正しく処理されておらず、基になるコントロールがこのコントロールの上に描画されていることが示されました。

2 番目の課題は、基になるコントロールが変更されたときに、コントロールが適切に再描画されるようにすることです。課題 1 で自動無効化を切り離すことにより、コントロールにそれ自体を無効にするように通知し、その親を無効にしないようにすることが難しくなります。

誰かがこの問題を完全に解決した場合は、コードを提供してください。そうでない場合は、問題の 1 つまたは複数の部分をどのように処理するかについての経験を提供してください。

どうもありがとう。

編集:

WS_EX_TRANSPARENT に従って WS_EX_TRANSPARENT に関する想定された詳細が表示されます- 実際には何をしますか?

調査の更新: ButtonRenderer.DrawParentBackground は、Application.EnableVisualStyles() が使用され、単に親の背景描画を強制する場合にのみ、実際には Control 自体によって使用されます。の同義語のようです

InvokePaintBackground(Parent, e.Graphics)

親コントロールのすべての背景描画の詳細を再現します。

4

2 に答える 2

2

必要な一般的な透明度コントロールを作成しました。解決策は、コントロールとそのすべての兄弟の親の詳細な内訳であり、InvokePaint()メソッドとInvokePaintBackground()メソッドに依存するOnPaintBackground()メソッドで再帰的な描画ルーチンを準備しました。 。連続して小さいクリップを定義し、下部のコントロールと交差することにより、この方法は描画のオーバーヘッドを最小限に抑えます。

  • 完全なコントロールには、兄弟コントロールのInvalidateメソッドを検出して応答する方法が含まれ、透明なコントロールのスタックを効率的に描画し、アニメーション化された基になるコントロールに完全なアルファチャネルオーバーレイを効果的に許可します。

  • コントロールは、視覚的に正確な透明性を提供しながら、子および親コントロールのすべての順列とインターリーブできます。

  • コントロールではヒットテストは考慮されていません。

  • このコントロールは、ペイントイベント中に描画が実行されないコントロールを上書きしません。これは大きな制限です。

  • コントロールを使用するには、ベースから継承し、OnPaintメソッドをオーバーライドしてカスタム描画を実行します。基本メソッドの呼び出しが最初に呼び出される限り、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, 0, 0, 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, 0, 0, 1, initialTransform.OffsetX + translation.X, 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
于 2012-08-24T03:11:15.507 に答える
0
Me.Visible = False

また

Me.Opacity = 0

また

Me.Hide()
于 2012-08-19T21:51:43.907 に答える