Cocoa Bridge -Common Lisp 簡單窗口繪圖實例 (教程翻譯)

Cocoa Bridge -Common Lisp 簡單窗口繪圖實例 (教程翻譯)

=== 原文地址: 網絡: http://trac.clozure.com/ccl/wiki/CocoaBridge 原文標題: Cocoa Bridge 翻譯者: FreeBlues 2013-07-21安全

===網絡

目錄

0 Cocoa 橋 Cocoa Bridge

如同在 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

1 組件使用 Elementary Usage

1.1 基本窗口

這裏有一個很是簡單的例子: 如何建立和繪製一個窗口.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)

你就會看到一個紅色的窗口翻譯

1.2 更多繪圖 More drawing

在 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).

相關文章
相關標籤/搜索