Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/svn/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#如何强制Panel1和Panel2的喷漆事件同时完成?_C#_Winforms_Bitmap_Paint_Splitcontainer - Fatal编程技术网

C#如何强制Panel1和Panel2的喷漆事件同时完成?

C#如何强制Panel1和Panel2的喷漆事件同时完成?,c#,winforms,bitmap,paint,splitcontainer,C#,Winforms,Bitmap,Paint,Splitcontainer,我有一个SplitContainer(确切地说是一个),我将它的两个面板视为一个画布来绘制。我使用Graphics.DrawImage方法分别在面板上绘制位图。我先刷新Panel1,然后刷新Panel2,这会导致垂直/水平撕裂-Panel1的绘制结束,然后开始Panel2的绘制-这就是原因。我的问题的解决办法是什么?我使用splitContainer作为具有before/after功能的“位图视频流”的输出。也许我可以冻结用户界面直到Panel2_画画结束 private void sp

我有一个SplitContainer(确切地说是一个),我将它的两个面板视为一个画布来绘制。我使用Graphics.DrawImage方法分别在面板上绘制位图。我先刷新Panel1,然后刷新Panel2,这会导致垂直/水平撕裂-Panel1的绘制结束,然后开始Panel2的绘制-这就是原因。我的问题的解决办法是什么?我使用splitContainer作为具有before/after功能的“位图视频流”的输出。也许我可以冻结用户界面直到Panel2_画画结束

    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();
    }
也许我可以冻结用户界面直到Panel2_画画结束

    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();
    }
看看:

在控件上调用SuspendLayout(),执行所有图形操作,然后调用ResumeLayout()一次更新所有内容。该文档中有一个示例


如果绘图操作花费的时间太长,则临时图形工件mght开始出现在“冻结”区域中,直到ResumeLayout()之后。

查看文档以了解更多信息

从链接:

使控件的特定区域无效,并导致向控件发送绘制消息。(可选)使指定给该控件的子控件无效

因此,与其分别使每个面板无效,只需调用此方法一次,它就可以执行您想要的操作。或者只修改一点代码:

if (refreshClipA && refreshClipB)
{
    splitContainer.Invalidate(true);
}
else
{
    if (refreshClipA)
    {
        splitContainer.Panel1.Refresh();
    }
    else if (refreshClipB)
    {
        splitContainer.Panel2.Refresh();
    }
}
基本上,我正在做的是,如果两个容器都需要重新喷漆,让
splitContainer
处理它,否则单独检查每个容器,并在需要时进行喷漆

从@DonBoitnott的评论开始,而不是使用
Invalidate(true)
使用文档中的以下内容:

强制控件使其客户端区域无效,并立即重新绘制自身和所有子控件


因此,只需将
splitContainer.Invalidate(true)
更改为
splitContainer.Refresh()

,就可以确保两个单独的panel.Paint()事件同时完成,至少在WinForms项目中是不可能的。唯一对我有效的解决方案是DonBoitnott提出的建议。我现在使用单个面板并模拟splitcontainer行为

如果我回答这个问题,我建议您放弃splitcontainer并渲染到单个曲面,这样您总是处于单个绘制事件中,只需将其区域化并相应地绘制即可DonBoitnott2016年2月17日17:51


我认为布局方法与绘画无关。它们与布局(大小、位置等)有关。诚然,如果你正在更改布局相关的项目,暂停布局将为中间布局节省一些绘画时间,但我不认为这是OP所说的。@Damien_,不信者,哦,对此表示抱歉。我认为这会阻止所有影响外观的操作,包括光栅绘制区域。不幸的是,挂起窗体或SplicContainer的布局不是一个解决方案。我已经检查过很多次了。我也在玩失效。这似乎与单独的提神相比没有什么区别。此外,它还破坏了基于backgroundworker@kagetoki您不能使用线程来解决此问题,因为这一切都必须在UI线程上完成,所以唯一的方法是让父控件处理任何图形或使用它。如果你想让两个视频播放器并排播放,那么使用面板和位图可能不是解决问题的方法go@kagetoki或者,如果您只知道图像的一小部分发生了更改,则只能重新绘制面板的一个区域fyi,区别在于
Invalidate
:“导致发送绘制消息”和“刷新”:“强制控件使其客户端区域无效,并立即重新绘制自身“。您无法控制控件何时响应重新绘制的请求。@kagetoki我确实看到了。如果我回答这个问题,我建议您放弃splitcontainer并渲染到单个曲面,这样您总是处于单个绘制事件中,您只需将其分区并相应地绘制。我希望有一种方法可以冻结splitcontainer,直到我说它可以再次恢复。不过,我认为没有这样的方法。最糟糕的方法可能是在Panel1 unitl Panel2_Paint ends上用上一个位图覆盖一个picturebox,对吗?是不是太肮脏和效率低下?你可能不能强迫两个面板同时油漆。我现在用一块面板来画画。我将位图的一部分绘制在面板上。我将鼠标单击视为上一个拆分器移动事件。这是一个更有效的解决方案。如果你和我有同样的问题,首先要抛弃SplitContainer。我没有写它,但在我问这个问题之前,我已经找到了一种在同一时间绘画的方法——尽管不要使用它,因为它绝对是一种非常肮脏和浮华的方法。我在Panel1和Panel2上停靠了两个PictureBox,并使用了它的Image属性。