21

我想知道小部件在哪些情况下会收到它的绘制事件,以及它如何随操作系统而变化。

paintEvent 的 Qt 文档只说

绘制事件是重新绘制全部或部分小部件的请求。它可能由于以下原因之一发生:

调用了 repaint() 或 update(),

小部件被遮挡,现在已被发现,或者

许多其他原因。

到目前为止,我已经在paintEvent中添加了一些痕迹,

void Widget::paintEvent(QPaintEvent *e)
{
    static int count = 0;
    qDebug("paintEvent, %d", count++);
}

这就是我发现的(至少在 Windows 7 上):

当小部件失去/获得焦点时调用paintEvent。当另一个小部件经过我们的小部件时,不会调用绘制事件。我不知道这是否是因为 Windows 7 合成。当最小化的窗口被恢复时,paintEvent 也会被调用。调整大小时调用paintEvent。

那么行为是否依赖于操作系统?

4

1 回答 1

21

是的,在您描述的意义上,它取决于操作系统。

桌面窗口管理器 (DWM),位于 Windows Vista 和 7 中,负责桌面组合、Aero 玻璃效果和其他各种吸引人的小工具,其工作方式与以前版本的 Windows 中使用的模型略有不同. 正如您所怀疑的那样,它会为您的窗口缓存位图,即使它们不可见,因为它们被另一个窗口遮挡。这意味着它不需要您重新绘制它们(因此它不会引发绘制事件),因为它可以从缓存的位图中对它们进行 blit。这不仅是对每个应用程序自身重绘的潜在优化,它还允许 DWM 实现诸如 Aero Flip 之类的东西,为此它使用其缓存的位图。

一个例外是,例如,CS_SAVEBITS班级风格一直如此。如果 DWM 缓存的位图已失效(例如,因为您的窗口图像已更改),它将丢弃它并要求您重新绘制窗口。

通过关闭 DWM 组合(切换到“Windows 经典”主题)来测试这个理论,然后遮盖您的窗口以查看您是否收到绘制事件。您应该,就像您在所有以前版本的 Windows 中所做的那样。

但更重要的一点是,您不应依赖以任何特定顺序接收绘制事件。关于绘制事件,您应该假设的唯一一件事是,当操作系统需要您重新绘制窗口时,您会收到一个。否则,它不会打扰你。我确信这就是文档满足于在这一点上含糊其辞的原因,超出了可能的技术限制。

这就是为什么逻辑不应该进入绘制事件处理程序内部的原因。该方法应该负责的唯一事情是按当前状态重新绘制窗口。该状态需要保存在其他地方。此规则也是可交换的:您不应在绘制事件处理程序之外进行任何绘制。

当然,您始终可以通过使窗口无效来强制引发绘制事件(我确定 Qt 有一个invalidateorrefresh方法,请查看文档),但这并不意味着放置应用程序逻辑的好模式在处理此事件的方法中。

于 2012-07-25T08:49:02.453 回答