0

私は SplitContainer (正確にはNonFlickerSplitContainerの1 つ) を持っており、その両方のパネルをペイントする単一のキャンバスとして扱います。Graphics.DrawImage メソッドを使用して、パネルにビットマップを個別に描画します。最初に Panel1 を更新し、次に Panel2 を更新すると、垂直/水平の引き裂きが発生します - Panel1 の描画が終了し、次に Panel2 の描画が開始されます - これが理由です。私の問題の解決策は何ですか?ビフォア/アフター機能を備えた「ビットマップ ビデオ ストリーム」への出力として、splitContainer を使用します。Panel2_Paint が終了するまで、どうにかして UI をフリーズできますか?

    private void splitContainer_Panel1_Paint(object sender, PaintEventArgs e)
    {
        if (frameA != null)
        {
            if (ORIGINAL_SIZE_SET)
                e.Graphics.DrawImage(frameA, 0, 0);
            else
                e.Graphics.DrawImage(frameA, 0, 0, ClientSize.Width, ClientSize.Height);
        }
    }

    private void splitContainer_Panel2_Paint(object sender, PaintEventArgs e)
    {
        if (frameB != null)
        {
            //...

            if (ORIGINAL_SIZE_SET)
                e.Graphics.DrawImage(frameB, x, y);
            else
                e.Graphics.DrawImage(frameB, x, y, ClientSize.Width, ClientSize.Height);
        }
    }

    private Bitmap frameA = null;
    private Bitmap frameB = null;

    private void RefreshOutput(bool refreshClipA = true, bool refreshClipB = true)
    {
        if (refreshClipA)
        {
            frameA = GetVideoFrame(...);

            //...
        }

        if (refreshClipB)
        {
            frameB = GetVideoFrame(...);

            //...
        }

        if (refreshClipA)
            splitContainer.Panel1.Refresh();

        if (refreshClipB)
            splitContainer.Panel2.Refresh();
    }
4

3 に答える 3

0

Panel2_Paint が終了するまで、どうにかして UI をフリーズできますか?

見てみましょう: https://msdn.microsoft.com/en-us/library/system.windows.forms.control.suspendlayout(v=vs.110).aspx

コントロールで SuspendLayout() を呼び出し、すべてのグラフィック操作を実行してから ResumeLayout() を呼び出して、すべてを一度に更新します。そのドキュメントに例があります。

描画操作に時間がかかりすぎると、ResumeLayout() の後まで、一時的なグラフィック アーティファクトが「凍結」領域に表示され始めます。

于 2016-02-17T15:12:57.237 に答える
0

のドキュメントを参照してくださいSplitContainer.Invalidate(bool invalidate Children)

リンクから:

コントロールの特定の領域を無効にし、ペイント メッセージがコントロールに送信されるようにします。オプションで、コントロールに割り当てられた子コントロールを無効にします。

したがって、各パネルを個別に無効にする代わりに、このメソッドを一度呼び出すだけで、必要なことが行われます。または、コードを少しだけ変更するには:

if (refreshClipA && refreshClipB)
{
    splitContainer.Invalidate(true);
}
else
{
    if (refreshClipA)
    {
        splitContainer.Panel1.Refresh();
    }
    else if (refreshClipB)
    {
        splitContainer.Panel2.Refresh();
    }
}

基本的に私がやっていることは、両方とも再描画が必要な場合はsplitContainer処理させ、そうでない場合はそれぞれを個別にチェックし、必要に応じて描画することです。

@DonBoitnott のコメントから、ドキュメントの which をInvalidate(true)使用する代わりにRefresh():

コントロールのクライアント領域を強制的に無効にし、それ自体とすべての子コントロールをすぐに再描画します。

に変更splitContainer.Invalidate(true)するだけsplitContainer.Refresh()です。

于 2016-02-17T15:24:58.350 に答える
0

少なくとも WinForms プロジェクトでは、2 つの個別の panel.Paint() イベントが同時に完了することを確認することは不可能です。私にとってうまくいった唯一の解決策は、DonBoitnott によって提案されたものです。現在、単一のパネルを使用して、splitcontainer の動作をシミュレートしています。

私がこれに答えるなら、splitcontainer を捨てて 1 つのサーフェスにレンダリングすることをお勧めします。そうすれば、常に 1 つの Paint イベントにいて、単純にそれをリージョン化してそれに応じて描画できます。—ドンボイトノット

于 2017-01-22T09:36:28.757 に答える