0

I need to repeatedly redraw a window showing some form of continous analysis. Now:

1) If I do that in WM_PAINT after the painting, I basically kill everyone else's painting, so it's not usable.

2) If I do that in a timer, it is kind of lagging.

So what is the best way to do that so the window is frequently repainted, but when the OS is busy processing some data or by painting other applications, it lowers the rate. I always thought the OS should take care of distributing the CPU power between the processes leaving the graphics secondary to ensure actual processing has enough time, but it doesn't look so on Windows nor on Mac.

Vojtěch Melda Meluzín
  • 1,117
  • 3
  • 11
  • 22
  • 1
    If you change the data behind the view displaying it, `InvalidateRect()` to trip the paint-bit should be ok. You don't need to invalidate any region besides the one that is updated, however, so you may want to take the extra measure to do that. But **never** `InvalidateRect` after you finish a `WM_PAINT` (i.e. after your `EndPaint`. That is insanity. Instead post a thread-event or user-event to your queue from your data-calc code and have *that* handler in your window proc `InvalidateRect` and *possibly* `UpdateWindow`. – WhozCraig Jan 06 '14 at 23:52
  • Well that's more or less what i'm doing now. The extreme thing with invalidating in wm_paint i tried just for "fun", it really doesn't make much sense. Though if the os would distribute the cpu well, this would be ideal to get maximum framerate without filling the queue with requests. – Vojtěch Melda Meluzín Jan 07 '14 at 11:20
  • The cocoa tag was because i'm interested in the same thing on macs. – Vojtěch Melda Meluzín Jan 07 '14 at 11:21

1 Answers1

1

Typically you would create a timer and invalidate the window at each timer tick. If there is a lag, it could be that the update frequency is too high, or the processing performed in the paint method is too expensive.

Keep in mind that games with complex 3D scenes routinely achieve 60fps (and higher). So high framerate updates are certainly possible.

Note that under Windows, the WM_TIMER event is notoriously inconsistent. You may need to explore other high-resolution timers if you need more than ~1 second resolution.

On the Mac, you can create an NSTimer and call setNeedsDisplay:YES on your NSView. Something like this:

// 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];
}

The NSTimer in Cocoa is quite reliable, so the above should work just fine, even for quite fast updates.

If you need to update at frame-rate (ie. 25fps) have a look at the CVDisplayLink support. This is really only needed for video applications and the like.

gavinb
  • 19,278
  • 3
  • 45
  • 60
  • Thanks, that's what i want to try now. Btw really 1 second resolution? – Vojtěch Melda Meluzín Jan 07 '14 at 11:24
  • 1
    Well, `WM_TIMER` is problematic as multiple events can get coalesced as they are implemented as a flag in `GetMessage()`. If you need accurate timers, there are several options. Look at multimedia timers, for example. You don't mention which frameworks you are using, but this comparison http://msdn.microsoft.com/en-us/magazine/cc164015.aspx is worth reading. – gavinb Jan 08 '14 at 00:37