强制PyGtk主窗口重绘
我有一个这样的用户界面结构:
1个水平框 -> 8个垂直框 -> 2个部分(GObject) -> 1个矩形小部件(gtk.DrawingArea)
简单来说,这就是一个包含16个cairo矩形的表格,分成两行。
这个cairo矩形小部件本身是gtk.DrawingArea的一个子类,并且有一个叫做expose-handler的处理函数。
我现在重写了程序,数据结构和用户界面完全分开了。后台有一个线程在运行,更新数据结构。在用户界面前面调用了gobject.threads_init()
。在100毫秒的超时后,gobject.timeout_add(100, self.update_widget)
,主线程发出一个信号,但只有第一个小部件能接收到。
这是expose-handler的代码:
def OnDraw(self, widget, event):
# self.window / widget.window works both
ctx = widget.window.cairo_create()
ctx.save()
rect = self.get_allocation()
ctx.rectangle(50, 0, 30, rect.height)
ctx.set_source_rgb(*self._BACKGROUND_RGB)
ctx.fill()
ctx.rectangle(0, rect.height * (1. - self.section.GetLevel()), rect.width, rect.height)
ctx.clip()
ctx.set_source_surface(self.source, 0, 0)
ctx.paint()
ctx.restore()
return False
#_____________________________________________________________________
def update_widget(self):
rect = self.get_allocation()
self.window.invalidate_rect(rect, False)
while gtk.events_pending():
gtk.main_iteration(False)
return True
#_____________________________________________________________________
注意:
如果我最小化并恢复窗口,小部件会接收到信号并更新。
我尝试了不同的方法,包括线程和不同的信号传递……所有方法都导致了上述相同的行为。
我该如何强制gtk.main返回并重新绘制其他小部件呢?
2 个回答
在100毫秒的超时后,使用gobject.timeout_add(100, self.update_widget)
尝试在没有gobject.timeout_add()的情况下让GUI线程运行,把其他计算放在另一个线程里。
gobject.timeout_add看起来像是一个独立的线程,而gtk无法正常与它协作。
我程序的一部分(它能正常工作):
def init_tr_modules(self):
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
window.set_title("Checking internet connection")
window.set_border_width(2)
window.set_icon(app_gui.icon)
window.set_geometry_hints(None, 510, 27)
vbox = gtk.VBox(False, 1)
vbox.set_border_width(1)
window.add(vbox)
pbar = gtk.ProgressBar()
vbox.pack_start(pbar, False, False, 1)
window.set_position(gtk.WIN_POS_CENTER)
window.set_resizable(False)
pbar.set_text("Wait")
pbar.set_pulse_step(0.01)
window.show_all()
tr_thread = \
threading.Thread(target = self.init_tr_services)
tr_thread.start()
while self.queue.qsize() == 0:
while gtk.events_pending():
gtk.main_iteration(False)
pbar.pulse()
sleep(0.05)
while self.queue.qsize():
self.queue.get()
window.set_title("Get list")
pbar.set_fraction(0.005)
while gtk.events_pending():
gtk.main_iteration(False)
for i in self.tr_services:
pbar.set_text(i.service.get_service_name())
tr_thread = \
threading.Thread(target = i.service.renew_list)
tr_thread.start()
while self.queue.qsize() == 0:
while gtk.events_pending():
gtk.main_iteration(False)
while self.queue.qsize():
self.queue.get()
new_val = pbar.get_fraction() + (1.0-0.006) / len(self.tr_services)
pbar.set_fraction(new_val)
window.destroy()
#end def
所有非图形界面的操作都隐藏在非主线程中。主线程负责图形界面。
希望这能帮到你,如果我理解问题正确的话。 :)
试试 mainHbox.queue_draw()
这个命令。
如果这个方法不管用,那就遍历所有的 RectangleWidget 对象,然后重新绘制它们:
for vbox in mainHbox.get_children():
for hbox in vbox.get_children():
for widget in hbox.get_children():
widget.queue_draw()
如果你使用的是 Table
,那就更简单了……