=== 原文地址: 网络: http://trac.clozure.com/ccl/wiki/CocoaBridge 原文标题: Cocoa Bridge 翻译者: FreeBlues 2013-07-21安全
===网络
如同在 OpenMCL FFI 章节中讨论的那样(http://trac.clozure.com/ccl/wiki/OpenMclFfi), OpenMCL 拥有一个很是强大的接口, 对于存在于 Lisp 的映像以外的接口库和组件的世界而言. 其中最重要的是 Cocoa 桥,一个 Mac OS X 用户接口的绑定层。函数
一本很好的介绍 Cocoa 的读物是 Aaron Hillegass 的 <Cocoa Programming for Mac OS X>(http://www.amazon.com/Cocoa-Programming-Mac-OS-2nd/dp/0321213149).ui
这里有一个很是简单的例子: 如何建立和绘制一个窗口.url
(in-package "CL-USER") (require "COCOA") (defclass red-view (ns:ns-view) () (:metaclass ns:+ns-object)) (objc:defmethod (#/drawRect: :void) ((self red-view) (rect :<NSR>ect)) (#/set (#/redColor ns:ns-color)) (#_NSRectFill (#/bounds self))) (defun show-red-window () (ccl::with-autorelease-pool (let* ((rect (ns:make-ns-rect 0 0 300 300)) (w (make-instance 'ns:ns-window :with-content-rect rect :style-mask (logior #$NSTitledWindowMask #$NSClosableWindowMask #$NSMiniaturizableWindowMask) :backing #$NSBackingStoreBuffered :defer t))) (#/setTitle: w #@"Red") (#/setContentView: w (#/autorelease (make-instance 'red-view))) (#/center w) (#/orderFront: w nil) (#/contentView w))))
加载包括这些语句形式的文件(直接把上述代码拷贝到 CCL 的 REPL 中, 而后按回车便可), 而后对下属语句形式求值:线程
(show-red-window)
你就会看到一个红色的窗口翻译
在 Cocoa 中通常的假设是你会在您的自定义视图的 drawRect: 方法里作您的绘图。不过,若是可以在 lisp 顶层经过求值形式来绘制, 每每是不错的。code
有一个随之而来的问题,至少在 OpenMCL 中,部分的 Cocoa 不是线程安全的。幸运的是,支持在辅助线程里建立窗口。所以绘制一个视图,经过调用 lockFocusIfCanDraw 和 unlockFocus 来提供绘制。orm
所以,要保持忘记 unlockFocus,定义这个简单的宏。(若是你忘记 unlockFocus,你会获得一个旋转的沙滩球而且不得不干掉 Lisp。)对象
(defmacro with-focused-view (view &body forms) `(when (#/lockFocusIfCanDraw ,view) (unwind-protect (progn ,@forms) (#/unlockFocus ,view) (#/flushGraphics (#/currentContext ns:ns-graphics-context)) (#/flushWindow (#/window ,view)))))
flushGraphics/flushWindow 确保您的即时绘图被显示出来。
首先,建立一个窗口。(注意,函数 show-red-window 返回一个视图实例。)
(setf *v* (show-red-window))
如今, 有了一个视图实例在手, 你能够绘图了
(with-focused-view *v* (let* ((path (#/bezierPath ns:ns-bezier-path))) (#/moveToPoint: path (ns:make-ns-point 10 10)) (#/lineToPoint: path (ns:make-ns-point 100 100)) (#/stroke path) (#/drawAtPoint:withAttributes: #@"hello world" (ns:make-ns-point 10 100) +null-ptr+)))
开始有点爱好者,咱们能够编写代码来从网络上抓取一个图像并把它绘制在咱们的视图中. 这一次, 咱们使用 Objective-C 语言风格习惯建立一个 NSImage 对象实例。咱们也能够写成这种 Lisp 语言风格:
(make-instance 'ns:ns-image :with-contents-of-url url)
请注意,您必须释放 NSImage 对象实例,无论你是如何建立它的。(当窗口关闭时, 在上述 show-red-window 中建立的 NSWindow 实例将被释放,因此没有内存泄漏. 可是,这是 NSWindow 类的一种特殊功能。)
(defun draw-earth (view) (let* ((url (#/URLWithString: ns:ns-url #@"http://nssdc.gsfc.nasa.gov/thumbnail/planetary/earth/apollo17_earth.gif")) (image (#/initWithContentsOfURL: (#/alloc ns:ns-image) url)) (alpha (float 1.0 ns:+cgfloat-zero+))) (with-focused-view view (ns:with-ns-rect (z 0 0 0 0) (#/drawAtPoint:fromRect:operation:fraction: image (ns:make-ns-point 40 40) z #$NSCompositeCopy alpha))) (#/release image)))
进行实际的绘制
(draw-earth *v*)
咱们经过在 listener(即 REPL) 中求值形式进行的绘制, 能够被看做是“直接模式”绘图。这是一个有趣的实验,但若是视图被告知从新显示其自己时(例如,若是你最小化,而后恢复窗口), 你的绘图将被一扫而光。你须要为您的绘图程序安排, 使其被视图的 drawRect:方法来调用,由于它的绘图是“永久的”。
附录:完整的绘图代码:
(in-package "CL-USER") (require "COCOA") (defclass red-view (ns:ns-view) () (:metaclass ns:+ns-object)) (objc:defmethod (#/drawRect: :void) ((self red-view) (rect :<NSR>ect)) (#/set (#/redColor ns:ns-color)) (#_NSRectFill (#/bounds self))) (defun show-red-window () (ccl::with-autorelease-pool (let* ((rect (ns:make-ns-rect 0 0 300 300)) (w (make-instance 'ns:ns-window :with-content-rect rect :style-mask (logior #$NSTitledWindowMask #$NSClosableWindowMask #$NSMiniaturizableWindowMask) :backing #$NSBackingStoreBuffered :defer t))) (#/setTitle: w #@"Red") (#/setContentView: w (#/autorelease (make-instance 'red-view))) (#/center w) (#/orderFront: w nil) (#/contentView w)))) (show-red-window) (defmacro with-focused-view (view &body forms) `(when (#/lockFocusIfCanDraw ,view) (unwind-protect (progn ,@forms) (#/unlockFocus ,view) (#/flushGraphics (#/currentContext ns:ns-graphics-context)) (#/flushWindow (#/window ,view))))) (setf *v* (show-red-window)) (with-focused-view *v* (let* ((path (#/bezierPath ns:ns-bezier-path))) (#/moveToPoint: path (ns:make-ns-point 10 10)) (#/lineToPoint: path (ns:make-ns-point 100 100)) (#/stroke path) (#/drawAtPoint:withAttributes: #@"hello world" (ns:make-ns-point 10 100) +null-ptr+))) (defun draw-earth (view) (let* ((url (#/URLWithString: ns:ns-url #@"http://nssdc.gsfc.nasa.gov/thumbnail/planetary/earth/apollo17_earth.gif")) (image (#/initWithContentsOfURL: (#/alloc ns:ns-image) url)) (alpha (float 1.0 ns:+cgfloat-zero+))) (with-focused-view view (ns:with-ns-rect (z 0 0 0 0) (#/drawAtPoint:fromRect:operation:fraction: image (ns:make-ns-point 40 40) z #$NSCompositeCopy alpha))) (#/release image))) (draw-earth *v*)
运行截图以下:
可参考: GradientWindow(http://trac.clozure.com/ccl/wiki/GradientWindow), EasyGuiCurrencyConverter(http://trac.clozure.com/ccl/wiki/EasyGuiCurrencyConverter).