C# 如何强制 Panel1 和 Panel2 的 Paint 事件同时完成
本文关键字:事件 Paint 何强制 Panel1 Panel2 | 更新日期: 2023-09-27 18:35:06
我有一个SplitContainer(确切地说是NonFlickerSplitContainer),我将它的两个面板都视为一个画布来绘画。我使用Graphics.DrawImage方法在面板上分别绘制位图。我首先刷新 Panel1,然后刷新 Panel2,这会导致垂直/水平撕裂 - Panel1 的绘画结束,然后 Panel2 的绘画开始 - 这就是原因。我的问题的解决方案是什么?我使用 splitContainer 作为具有之前/之后功能的"位图视频流"的输出。也许我可以以某种方式冻结 UI,直到Panel2_Paint结束?
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();
}
查看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的评论开始,而不是使用Invalidate(true)
使用文档中的Refresh()
:
强制控件使其工作区失效,并立即重绘自身和任何子控件。
因此,只需将splitContainer.Invalidate(true)
更改为splitContainer.Refresh()
即可。
也许我可以以某种方式冻结 UI 直到Panel2_Paint结束?
看看: https://msdn.microsoft.com/en-us/library/system.windows.forms.control.suspendlayout(v=vs.110).aspx
在控件上调用 SuspendLayout(),执行所有图形操作,然后调用 ResumeLayout() 以一次性更新所有内容。 该文档中有一个示例。
如果绘制操作花费的时间过长,则临时图形伪影将开始出现在"冻结"区域中,直到 ResumeLayout() 之后。
我经历过不可能确保两个单独的面板。Paint() 事件在同一时刻完成,至少在 WinForms 项目中不会。唯一对我有用的解决方案是DonBoitnott的建议。我现在使用单个面板并模拟拆分容器行为。
如果我回答这个问题,我建议你放弃拆分容器并渲染到单个表面,这样你总是在单个 Paint 事件中,你只需将其区域化并相应地绘制即可。 – DonBoitnott 二月 17 '16 在 17:51