我可以在使用同一窗口上的另一个控件时重绘自定义NSView吗?

时间:2012-12-18 13:18:02

标签: cocoa user-interface window nsview

在我正在处理的程序中,我正在执行大量数据处理,并且希望能够绘制自定义NSView以直观地表示该过程。

使用GCD从主线程处理数据处理(使用dispatch_sync作为需要保留的顺序):

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!
    });
}

当处理开始时,我初始化一个计时器,用于要求自定义显示器定期重绘(一旦完成所有处理任务,该计时器就会失效):

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

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

我按预期工作了,但是我现在注意到的唯一问题是,如果我执行某项操作,例如单击并按住同一窗口上的按钮,或者在进程进行时开始拖动滑块,则重绘直到我放开鼠标才会阻止自定义视图!

有什么方法可以防止这种情况发生,最好不要将所有控件移到单独的窗口上!

2 个答案:

答案 0 :(得分:3)

yip计时器在runloop上,而在拖放/跟踪模式下,它不会被解雇,因为runloop不是普通模式的高级

将其添加到所需的模式中:

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

编辑:runloop基本上是苹果的循环,用于向应用程序发送任何事件。并根据所谓的模式过滤它调度的事件。

答案 1 :(得分:0)

谢谢大家提出的问题,答案和评论。

使用NSEventTrackingRunLoopMode解决了我不断重绘具有给定参数的OpenGL视图的情况。

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
  }

}

现在它继续绘图,我拖动滑块来更新其参数。此外,调整窗口的大小变得平滑。

对于其他解决方案&#34;异步进行,&#34;有趣!我稍后会试试。谢谢!

<强>编辑:

我已经改变主意使用NSRunLoopCommonModes(RunLoopMode.commonModes),而不是NSEventTrackingRunLoopMode。

两者都运作良好,但Apple的文件暗示共同模式在我的情况下更好。

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