Can I redraw a custom NSView while another control on the same window is being used?

梦想与她 提交于 2019-12-24 07:06:21

问题


In a program I am working on I am performing a large amount of data crunching, and want to be able draw a custom NSView to represent the process visually.

The data crunching is processed off the main thread by using GCD (using dispatch_sync as the order needs to be preserved):

for (int i=0; i<iterations; i++) {

    dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // Add a data crunching task to the queue!
    });
}

When the processing is started I initialise a timer, which is used to ask the custom display to redraw at regular intervals (this timer is invalidated once all of the processing tasks are completed):

-(void)onTick:(NSTimer *)timer {

    [_customView setNeedsDisplay:YES];
    // Update some other UI object (labels etc.)    
}

I have this working as expected, however the only problem I notice now is that if I do something like click and hold on a button on the same window, or begin dragging a slider while the process is going on, the redrawing of the custom view is prevented until I let go of the mouse!

Is there any way I can prevent this from happening, preferably without moving all of the controls onto a separate window!


回答1:


yip the timer is on the runloop and while in the drag drop / tracking mode it doesnt get fired because the runloop isnt advanced for the common mode

add it to the modes needed:

NSRunLoop *runloop = [NSRunLoop currentRunLoop];
NSTimer *timer = [NSTimer timerWithTimeInterval:0.1 target:self selector:@selector(myTimerAction:) userInfo:nil repeats:YES];
[runloop addTimer:timer forMode:NSRunLoopCommonModes];
[runloop addTimer:timer forMode: NSEventTrackingRunLoopMode];

edit: the runloop is basically apple's while loop for dispatch ANY event to an app. and it filters the events it dispatches based on so called modes.




回答2:


Thank you all for the question, answers and comments.

Use of NSEventTrackingRunLoopMode has solved my case that constantly redrawing an OpenGL view with given parameters.

class MyOpenGLView: NSOpenGLView {

  var timer: Timer?

  required init?(coder: NSCoder) {
    super.init(coder: coder)

    timer = Timer.scheduledTimer(withTimeInterval: 1.0/60, repeats: true) { (t) in
      self.needsDisplay = true
    }

    let runloop = RunLoop.current
    runloop.add(timer!, forMode: .commonModes)
    // runloop.add(timer!, forMode: .eventTrackingRunLoopMode)
  }

  override func draw(_ dirtyRect: NSRect) {
    // draw moving 3D-cubes
  }

}

Now it keeps drawing even I am dragging a slider to update its parameters. Additionally, resizing window has become smooth.

For other solutions "Do it asynchronously," interesting! I will give it try later. Thanks!

EDITED:

I have changed my mind to use NSRunLoopCommonModes (RunLoopMode.commonModes), instead of NSEventTrackingRunLoopMode.

Both works well, but Apple's document implies that Common Modes is better in my case.

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html



来源:https://stackoverflow.com/questions/13933902/can-i-redraw-a-custom-nsview-while-another-control-on-the-same-window-is-being-u

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!