如何在PyGTK中刷新DrawingArea?

2 投票
1 回答
1504 浏览
提问于 2025-04-15 23:29

我用Glade创建了一个界面,里面有一个绘图区域和一些按钮。

我尝试创建一个线程,让我的画布每隔一段时间刷新一次。但是过了几秒钟,我就收到了错误信息,比如:

“X Window Server 0.0”,“致命错误 IO 11”

这是我的代码:

import pygtk
pygtk.require("2.0")
import gtk
import Canvas
import threading as T
import time
import Map

gtk.gdk.threads_init()

class Interface(object):
    class ThreadCanvas(T.Thread):
        """Thread to display the map"""
        def __init__(self, interface):
            T.Thread.__init__(self)
            self.interface = interface
            self.started = True
            self.start()

        def run(self):
            while self.started:
                time.sleep(2)
                self.interface.on_canvas_expose_event()

        def stop(self):
            self.started = False

    def __init__(self):
        self.interface = gtk.Builder()
        self.interface.add_from_file("interface.glade")

    #Map
    self.map = Map.Map(2,2)

        #Canva
        self.canvas = Canvas.MyCanvas(self.interface.get_object("canvas"),self.game)
        self.interface.connect_signals(self)

        #Thread Canvas
        self.render = self.ThreadCanvas(self)

    def on_btnChange_clicked(self, widget):
    #Change map
        self.map.change()

    def on_interface_destroy(self, widget):
        self.render.stop()
        self.render.join()
        self.render._Thread__stop()
        gtk.main_quit()

    def on_canvas_expose_event(self):
        st = time.time()
        self.canvas.update(self.map)
        et = time.time()
        print "Canvas refresh in : %f times" %(et-st)

    def main(self):
        gtk.main()

我该如何解决这些错误呢?

1 个回答

1

在PyGTK中使用Python线程时,你需要在访问共享的GTK对象时,使用 gtk.gdk.threads_enter()gtk.gdk.threads_leave() 来包裹这些操作。你也可以看看 threads_enter() 方法。

其实,使用GTK提供的定时调用函数可能更好,比如 timeout_add(...)timeout_add_seconds(...) (注意,这些函数最近有些位置变动,可能在你的安装中它们在GObject而不是GLib里)。

还有一些其他的注意事项:

  1. 在Python中,不建议像Java那样去子类化Thread对象。Python的做法是定义一个函数或可调用对象,然后把它传给Thread构造函数。
  2. 不要使用 _Thread__stop()。这个名字被处理过是有原因的,它是Thread对象内部机制的一部分,不是给普通用户使用的。你应该使用一些线程安全的对象(比如 Condition 对象),并在你传给Thread对象的函数中检查它。或者,你可以把你的Thread设置为守护线程,这样当程序退出时它会自动结束。
  3. GTKBuilder文件的常用扩展名是“.ui”,而不是“.glade”(尽管Glade本身默认会加上“.glade”作为扩展名)。

希望这些信息对你有帮助。

撰写回答