强制PyGtk主窗口重绘

2 投票
2 回答
2454 浏览
提问于 2025-04-17 13:36

我有一个这样的用户界面结构:
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 个回答

0

在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

所有非图形界面的操作都隐藏在非主线程中。主线程负责图形界面。

希望这能帮到你,如果我理解问题正确的话。 :)

2

试试 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,那就更简单了……

撰写回答