2010-08-18 83 views
3

我剛開始使用pycairo,並遇到以下有趣的錯誤。我編寫的程序創建一個簡單的gtk窗口,在其上繪製一個矩形,然後有一個回調在任何類型的鍵盤輸入上繪製一條隨機線。但是,似乎每個鍵盤輸入都必須創建一個新的上下文,否則在程序收到第一個鍵盤輸入(特別是在.stroke()行)時出現錯誤。錯誤如下,如果重要。 'BadDrawable(無效的Pixmap或Window參數)'。 (詳情:serial 230 error_code 9 request_code 53 minor_code 0)開羅上下文和持久性?

#! /usr/bin/env python 
import pygtk 
pygtk.require('2.0') 
import gtk, gobject, cairo, math, random 
# Create a GTK+ widget on which we will draw using Cairo 
class Screen(gtk.DrawingArea): 
# Draw in response to an expose-event 
    __gsignals__ = { "expose-event": "override" } 

    # Handle the expose-event by drawing 
    def do_expose_event(self, event): 
    # Create the cairo context 
    self.cr = self.window.cairo_create() 
    # Restrict Cairo to the exposed area; avoid extra work 
    self.cr.rectangle(event.area.x, event.area.y, event.area.width, event.area.height) 
    self.cr.clip() 

    self.draw(*self.window.get_size()) 

    def key_press_event(self, *args): 
    # print args 
    self.cr = self.window.cairo_create() # This is the line I have to add 
    # in order to make this function not throw the error. Note that cr is only 
    # given as attribute of self in order to stop it going out of scope when this line 
    # doesn't exist 
    self.cr.set_source_rgb(random.random(), random.random(), random.random()) 
    self.cr.move_to(*[z/2.0 for z in self.window.get_size()]) 
    self.cr.line_to(*[z*random.random() for z in self.window.get_size()]) 
    self.cr.stroke() 

    def draw(self, width, height): 
    # Fill the background with gray 
    self.cr.set_source_rgb(.5,.5,.5) 
    self.cr.rectangle(0, 0, width,height) 
    self.cr.fill() 

    self.cr.set_source_rgb(1,0,0) 
    self.cr.arc(width/2.0, height/2.0, min(width,height)/2.0 - 20.0, 0.0, 2.0*math.pi) 
    self.cr.stroke() 

#create a gtk window, attach to exit button, and whatever is passed as arg becomes the body of the window. AWESOME 
def run(Widget): 
    window = gtk.Window() 
    widget = Widget() 
    window.connect("delete-event", gtk.main_quit) 
    window.connect('key-press-event',widget.key_press_event) 
    widget.show() 
    window.add(widget) 
    window.present() 
    gtk.main() 

if __name__ == "__main__": 
    run(Screen) 

感謝您的幫助!

(更新:我打過來,我實現了以下內容:當我調整窗口的大小,添加的所有新對象被刪除(或者至少不會再出現)?)

+1

您可能對http://wiki.github.com/tbaugis/hamster_experiments/感興趣 - 它在開羅之上提供了一個相當有用的抽象。即使你不使用完整的庫,包含的tweener當然值得關注。 – 2010-08-19 12:41:13

回答

2

開羅圖紙不要堅持。 (最好不要將它們視爲「對象」 - 它不像一個畫布庫,在繪製它們之後可以移動它們或將它們轉換)。必須在曝光處理程序中執行所有繪製,或者它就像你發現的那樣,只要窗口重新繪製就會消失。

由於雙緩衝,cairo上下文不會持續:請參閱note in the C documentation,很遺憾,在PyGTK文檔中找不到任何地方。

在上面的代碼中,您應該在按鍵處理程序中生成隨機行的座標和顏色,並將它們保存在數組中。然後在公開處理程序中,依次繪製數組中的每一行。

+0

沉睡之後,我意識到這可能是類似於畫布的想法。感謝您填補開羅工作方式的空白。我想我沒有認真對待帆布比喻。 – 2010-08-19 16:08:43

0

許多持久的口味來討論:

圖紙上一些表面不堅持:GUI表面。你應該在揭露回調中重新繪製它們。

PyCairo對象不應該被視爲持久對象,僅作爲接口開羅庫的函數C.

開羅上下文的內容(路徑和填充)不會持續超過行程( )或fill()操作。

一個GUI表面的上下文不會在公開事件之間持續存在(因爲雙緩衝?)(我不知道上下文是否持續存在於其他表面上,即設備)。因此,您不能使用cairo上下文以存儲視口的屬性(窗口到文檔上,即用戶座標系中的模型)。

視覺持久性是人眼在光線停止後看到光線的傾向。幽靈和閃爍是動畫或視頻中的症狀。禁用雙緩衝可讓您在繪製事件時看到事物,即在一個公開事件中啓用動畫(模擬可視持久性的症狀)。禁用雙緩衝不會使暴露事件之間的GUI表面上的持續上下文保持不變。

記憶的持久性是你真正的持久性,或者我應該說超現實主義。