【问题标题】:What is to best approach to repeatedly invalidate a window using InvalidateRect?使用 InvalidateRect 反复使窗口无效的最佳方法是什么?
【发布时间】:2014-01-24 12:46:59
【问题描述】:

我需要反复重绘一个显示某种形式的连续分析的窗口。现在:

1)如果我在画完后在WM_PAINT中这样做,我基本上会杀死其他人的画,所以它不可用。

2) 如果我在计时器中这样做,那就有点滞后了。

那么最好的方法是什么,以便频繁地重新绘制窗口,但是当操作系统忙于处理某些数据或通过绘制其他应用程序时,它会降低速率。我一直认为操作系统应该负责在进程之间分配 CPU 功率,让图形处于次要位置,以确保实际处理有足够的时间,但在 Windows 和 Mac 上看起来都不是这样。

【问题讨论】:

  • 如果您更改显示它的视图后面的数据,InvalidateRect() 触发paint-bit 应该没问题。但是,您不需要使除已更新区域之外的任何区域无效,因此您可能需要采取额外措施来做到这一点。但是从不在你完成WM_PAINT 之后(即在你的EndPaint 之后)InvalidateRect。这太疯狂了。而是从你的数据计算代码向你的队列发布线程事件或用户事件并在您的窗口 proc InvalidateRect可能 UpdateWindow 中有 那个 处理程序。
  • 嗯,这或多或少是我现在正在做的事情。在 wm_paint 中无效的极端事情我只是为了“好玩”而尝试的,它真的没有多大意义。虽然如果操作系统能够很好地分配 cpu,这将是获得最大帧速率而不用请求填充队列的理想选择。
  • 可可标签是因为我对 mac 上的相同内容感兴趣。

标签: cocoa winapi paint wm-paint


【解决方案1】:

通常您会创建一个计时器并在每个计时器滴答时使窗口无效。如果有延迟,可能是更新频率太高,或者paint方法执行的处理成本太高。

请记住,具有复杂 3D 场景的游戏通常会达到 60fps(或更高)。如此高的帧率更新当然是可能的。

请注意,在 Windows 下,WM_TIMER 事件是出了名的不一致。如果您需要超过约 1 秒的分辨率,您可能需要探索其他高分辨率计时器。

在 Mac 上,您可以创建一个 NSTimer 并在您的 NSView 上调用 setNeedsDisplay:YES。像这样的:

// in your init... method
NSTimer* repaintTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
    target:self
    selector:@selector(timerTickHandler:)
    userInfo:nil
   repeats:YES];

// ...

-(void)timerTickHandler(NSTimer*)timer {
    [self.view setNeedsDisplay:YES];
}

Cocoa 中的NSTimer 非常可靠,因此上述内容应该可以正常工作,即使更新速度非常快。

如果您需要以帧速率(即 25fps)更新,请查看CVDisplayLink 支持。这实际上只需要视频应用程序等。

【讨论】:

  • 谢谢,这就是我现在想尝试的。顺便说一句,真的只有 1 秒的分辨率吗?
  • 好吧,WM_TIMER 是有问题的,因为多个事件可以合并为GetMessage() 中的标志。如果您需要准确的计时器,有多种选择。例如,查看多媒体计时器。您没有提及您正在使用哪些框架,但这个比较msdn.microsoft.com/en-us/magazine/cc164015.aspx 值得一读。
猜你喜欢
  • 1970-01-01
  • 2021-08-30
  • 2019-02-14
  • 2011-12-10
  • 2011-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-09
相关资源
最近更新 更多