【问题标题】:Swift on OS X: How to access the current CGContext for drawing in -[NSView drawRect:]OS X 上的 Swift:如何访问当前的 CGContext 以在 -[NSView drawRect:] 中绘图
【发布时间】:2015-05-23 06:51:49
【问题描述】:

设置:

Xcode 6.1
OS X 10.9.5
Swift Mac 基于文档的应用程序目标

问题:

我正在使用 Swift 制作 Cocoa Mac 应用程序(不是 iOS!)。我有一个自定义的NSView 子类。我想覆盖-drawRect:,并访问当前的CGContext 以使用CoreGraphics API 进行一些绘图。

但是,我似乎无法在 Swift 中访问当前的 CGContext(我在 ObjC 中做过数百次)。这是我的代码:

import Cocoa

class Canvas: NSView {
    override func drawRect(dirtyRect: CGRect) {
        if let ctx: CGContext! = NSGraphicsContext.currentContext()?.CGContext {
            // do drawing
        }
    }
}

当我运行时,我的drawRect 实现的第一行立即崩溃:

-[NSWindowGraphicsContext CGContext]: unrecognized selector sent to instance 0x60800005e840

我做错了什么?如何获取当前的CGContext 以在 Swift 中绘图?

注意:

我绝对想使用 CoreGraphics API。除非在 Swift 中使用 CoreGraphics API 是完全不可能的,否则请不要回复有关如何使用 AppKit 绘图 API 的建议(我不在乎它们是否更容易)。我想知道如何在 OS X 上使用 Swift 的 CoreGraphics。

【问题讨论】:

  • 在这里操作。发布此问题后,我立即意识到 -[NSGraphicsContext CGContext] 是 10.10 API。正如我所说,我正在开发 10.9(即使我的目标是使用 10.10 Base SDK)。所以,这就是问题所在。这个问题基本上是愚蠢的。这实际上是我编写的第一行 Swift 代码,所以我还在摸索,我只是假设我在语法上做错了什么。

标签: xcode macos cocoa swift cgcontext


【解决方案1】:

示例

Swift 3+

class CustomView: NSView {

    private var currentContext : CGContext? {
        get {
            if #available(OSX 10.10, *) {
                return NSGraphicsContext.current?.CGContext
            } else if let contextPointer = NSGraphicsContext.currentContext()?.graphicsPort {
                let context: CGContextRef = Unmanaged.fromOpaque(COpaquePointer(contextPointer)).takeUnretainedValue()
                return context
            }

            return nil
        }
    }

    private func saveGState(drawStuff: (ctx:CGContextRef) -> ()) -> () {
        if let context = self.currentContext {
            CGContextSaveGState (context)
            drawStuff(ctx: context)
            CGContextRestoreGState (context)
        }
    }

    override func drawRect(dirtyRect: NSRect) {
        super.drawRect(dirtyRect)

        saveGState { ctx in
            // Drawing code here.
        }
    }
}

斯威夫特 2

class CustomView: NSView {

    private var currentContext : CGContext? {
        get {
            if #available(OSX 10.10, *) {
                return NSGraphicsContext.currentContext()?.CGContext
            } else if let contextPointer = NSGraphicsContext.currentContext()?.graphicsPort {
                let context: CGContextRef = Unmanaged.fromOpaque(COpaquePointer(contextPointer)).takeUnretainedValue()
                return context
            }

            return nil
        }
    }

    private func saveGState(drawStuff: (ctx:CGContextRef) -> ()) -> () {
        if let context = self.currentContext {
            CGContextSaveGState (context)
            drawStuff(ctx: context)
            CGContextRestoreGState (context)
        }
    }

    override func drawRect(dirtyRect: NSRect) {
        super.drawRect(dirtyRect)

        saveGState { ctx in
            // Drawing code here.
        }
    }
}

【讨论】:

  • 这很优雅!但是,它只适用于 Swift 2?
  • 在 Swift 3+ 中使用 let ctx = NSGraphicsContext.current?.cgContext
【解决方案2】:

很遗憾,CGContext 仅在 10.10+ 中可用。还有graphicsPort,但它的类型为UnsafeMutablePointer<Void>(大概必须经过一番争论才能恢复一个可行的CGContext),并且在10.10 中已弃用。

如果这看起来不可行,您可以使用CGBitmapContextCreate 创建一个位图上下文并在其中绘制;然后您可以从中检索图像并绘制它以查看结果。

【讨论】:

  • 明白了,谢谢。看来我真的需要立即在 10.10 上进行开发,以使自己的事情变得更容易。现在就去做。
【解决方案3】:

Eporediese的答案可以更新为

斯威夫特 4

private var currentContext : CGContext? {
    get {
        if #available(OSX 10.10, *) {
            return NSGraphicsContext.current?.cgContext
        } else if let contextPointer = NSGraphicsContext.current?.graphicsPort {
            return Unmanaged.fromOpaque(contextPointer).takeUnretainedValue()
        }

        return nil
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-02-16
    • 2017-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-24
    • 2023-04-08
    • 1970-01-01
    相关资源
    最近更新 更多