让cocoa draw(_ dirtyRect)响应从不同类发送来的needsDisplay

问题描述 投票:0回答:1

我有一个带有两个视图的 macOS Swift 应用程序。一个是 Metal MTKView,它绘制一组动画 3D 对象,第二个是使用 BezierPath 绘制的图形。 Metal 视图控制器类称为 GameViewController,Metal 绘图是在其称为 Renderer 的委托中完成的。该图是在 GraphView 类的实例中完成的,并使用称为“graph”的插座连接到 GameViewController。这是代码的概要:

class GameViewController: NSViewController {

    @IBOutlet weak var graph: GraphView!
 
     @IBAction func h1_Slider(_ sender: NSSlider) {
        h1_length = sender.floatValue       
       dodraw()                 // This is only here to make a point about - it is not used normally
    }

    func dodraw() {
        graph.needsDisplay = true
        return
    }

<lots of other stuff to set up Metal drawing>

}

class Renderer: NSObject, MTKViewDelegate {

    public var graphRef = GameViewController()      //. Allows access to GameViewController from elsewhere

<lots of stuff to set up Metal>

   func draw(in view: MTKView) {    // Metal drawing loop
    
    grafRef.dodraw()        // this is supposed to cause GraphView to update its drawing
 
 <this is where the Metal drawing is done>
 
 }
} 

class GraphView:NSView
 {
    
    override func draw(_ dirtyRect:CGRect) {
        
        <This is where the Bezier drawing takes place in a View in the Storyboard View identified as an instance of GraphView
        
    }
    
 }


两个绘图组件单独工作都很好。我想连接它们。

基本上,Metal 绘图的内部循环每秒发生 60 次,通过引用 graphRef 调用 GameViewController 中的 dodraw() 方法。这应该将 GraphView 中的 needDisplay Bool 设置为 true,以便可以绘制图形。相反,我得到“致命错误:隐式展开可选值时意外发现 nil”,并且图形用红色下划线表示。我还进入 Xcode 输出窗口:“[Nib Loading] 无法将(控制器)出口从 (Vectors.GameViewController) 连接到 (MTKView):缺少设置器或实例变量”

如果我用 print("Q") 替换 dodraw() 方法中的“needsDisplay = true”并且不执行任何其他操作,则字母 Q 会在 Xcode 的输出窗口中打印多次。这表明Renderer中的graphRef链接工作正常。同样,如果我放回“graph.needsDisplay = true”并删除 Metal 绘图循环中的 dodraw() 调用,则当我在 GameViewController 类中移动滑块时会显示图形。这表明“graph.needsDisplay = true”语句似乎没有问题,并且graph.needsDisplay不为零。

我认为这是一个非常奇怪的行为:我似乎可以通过附加“图表”来调用needsDisplay = true命令。在它之前,我可以毫无困难地从 Metal 内循环引用 dodraw() 方法。唯一的麻烦是我不能同时做这些。出了什么问题?这是对 Swift 工作原理的误解吗?

swift cocoa
1个回答
0
投票

public var graphRef = GameViewController()
创建一个新的
GameViewController
。要使
graphRef
成为对 Storyboard 中现有
GameViewController
的引用,请将
graphRef
参数添加到
Renderer.init
并传递视图控制器。从 Xcode macOS 游戏模板开始:

class Renderer: NSObject, MTKViewDelegate {

    // other properties
    
    public var graphRef: GameViewController      //. Allows access to GameViewController from elsewhere

    init?(metalKitView: MTKView, graphRef: GameViewController) {
        self.graphRef = graphRef
        
        // other init stuff
    }
    
    // other methods
}

class GameViewController: NSViewController {

    // properties

    override func viewDidLoad() {
    
        // other stuff

        guard let newRenderer = Renderer(metalKitView: mtkView, graphRef: self) else {
            print("Renderer cannot be initialized")
            return
        }

        // other renderer stuff

    }
}
© www.soinside.com 2019 - 2024. All rights reserved.