Как внутренне обновить / перерисовать GTK Widget (GTKLabel) без события нажатия клавиши, используя python? - PullRequest
3 голосов
/ 05 декабря 2011

У меня есть некоторый код ниже, который пытается обновить элемент GTK Label. Я включаю два файла: файл пользовательского интерфейса и файл Py.

Файл пользовательского интерфейса:

<glade-interface>
  <widget class="GtkWindow" id="ApplicationFrame">
    <property name="width_request">320</property>
    <property name="height_request">240</property>
    <property name="visible">True</property>
    <property name="events">GDK_KEY_PRESS_MASK</property>
    <property name="title" translatable="yes">Simple</property>
    <property name="resizable">False</property>
    <property name="window_position">center-always</property>
    <property name="default_width">320</property>
    <property name="default_height">240</property>
    <property name="decorated">False</property>
    <property name="gravity">center</property>
    <child>
      <widget class="GtkFixed" id="layout">
        <property name="width_request">320</property>
        <property name="height_request">240</property>
        <property name="visible">True</property>
        <child>
          <widget class="GtkLabel" id="l1">
            <property name="width_request">320</property>
            <property name="height_request">40</property>
            <property name="visible">True</property>
            <property name="xalign">0</property>
            <property name="label" translatable="yes">l1</property>
          </widget>
          <packing>
            <property name="y">43</property>
          </packing>
        </child>
      </widget>
    </child>
  </widget>
</glade-interface>

Файл Python

import os
from time import sleep as wait
import gtk as gtk
import gtk.glade as glade
import gobject

class Application(object):
    def __init__ (self):
        self.glade = glade.XML("simple.ui")
        self.setup_ui()

    def setup_ui (self):
        self.window = self.glade.get_widget("ApplicationFrame")
        self.l1 = self.glade.get_widget("l1")
        self.names = {'l1' : self.l1}
        self.all = [self.l1]
        gobject.timeout_add(1000,self.display_me)
        gobject.timeout_add(100,self.do_something_that_takes_a_while)
        self.window.add_events(gtk.gdk.KEY_PRESS_MASK)
        self.window.connect("key-press-event", self.handler)
        self.window.connect("delete_event", self.delete_event)
        self.window.connect("destroy", self.destroy)
        self.window.show()

    def get_signal (self,widget,event):
        keyname = gtk.gdk.keyval_name(event.keyval)
        ctrl = event.state & gtk.gdk.CONTROL_MASK
        alt = event.state & gtk.gdk.MOD1_MASK
        shift = event.state & gtk.gdk.SHIFT_MASK
        name = []
        if ctrl and keyname not in ["Control_L","Control_R"]: 
            name.append("CTRL")
        if alt and keyname not in ["Alt_L","Alt_R"]:
            name.append("ALT")
        if shift and keyname not in ["Shift_L","Shift_R"]:
            name.append("SHIFT")
        name.append(keyname)
        name = "+".join(name)
        return name

    def handler (self,widget,event):
        name = self.get_signal(widget,event)
        if name.lower() in ['ctrl+x','ctrl+c','alt+q']:
            self.destroy()

    def main(self):
        gtk.main()

    def delete_event (self,widget=None,event=None,data=None):
        return False

    def destroy (self,widget=None,data=None):
        gtk.main_quit()

    def get (self,item):
        if isinstance(item, str): 
            if item in self.names:
                item = self.names[item]
        retval = None
        if hasattr(item,"text"):
            retval = item.text()
        elif hasattr(item,"get_label"):
            retval = item.get_label()
        return retval

    def set (self,item,text='',font=None):
        print 'Setting...'
        if isinstance(item, str): 
            if item in self.names:
                item = self.names[item]
        retval = None
        if font == None and hasattr(self,"page") and hasattr(self.page,"NORMAL_FONT"): 
                font = self.page.NORMAL_FONT
        if hasattr(item,"setText"):
            retval = item.setText(text)
        elif font == None:
            if hasattr(item,'set_text'):
                retval = item.set_text(text)
        elif hasattr(item,"set_label"):
            retval = item.set_label(text)
            if hasattr(item,"modify_font") and font != None:
                item.modify_font(font)
        item.queue_draw()
        self.try_to_update(item)
        print 'done'
        return retval

    def try_to_update (self,item):
        """
        do something here to update the visual screen????
        """
        print str(self)

    def do_something_that_takes_a_while (self):
        timeout = 15
        while timeout != 0:
            self.set('l1','%s' % timeout)
            wait(1)
            timeout -= 1
            print timeout
        return 1

    def clean (self):
        if item != None:
            self.set(item,empty_text)
        else:
            if hasattr(self,'all'):
                for item in self.all:
                    self.set(item)

    def display_me (self):
        print str(self)
        return True

    def __str__ (self):
        space = 25
        value = '%'+str(space)+'s'
        lines = ['\n','-'*79]
        if hasattr(self,'all'):
            line = []
            for obj in self.all:
                obj_value = self.get(obj)
                line.append(value % obj_value if obj_value != None else '')
                #line.append(value % ' ')
            lines.append(''.join(line))
        lines.append('-'*79)
        return '\n'.join(lines)


if __name__ == "__main__":
    from time import sleep as wait
    SEC = 1
    app = Application()
    app.main()

Это должно быть просто, но мне совершенно не хватает того, что я делаю неправильно. Элемент l1 не обновляется должным образом. Я думаю, что код внутри try_to_update - это то, где мне нужно обновить интерфейс, но я не знаю, какую функцию мне нужно вызвать. Может кто-нибудь помочь, пожалуйста?

Заранее спасибо!

Ответы [ 2 ]

9 голосов
/ 05 декабря 2011

Вы захотите использовать функцию queue_draw виджета:

Метод queue_draw_area () делает недействительной прямоугольную область виджета (...), вызывая метод gtk.gdk.Window.invalidate_rect() в окне виджета и во всех его дочерних окнах.

Но, поскольку вы уже делаете это в вашем set методе, я предполагаю, что

if hasattr(item,'show')

проверка запрещает обновление элемента. Еще одна проверка - вызвать функцию queue_draw для всего окна и посмотреть, обновляет ли она что-либо.

В качестве альтернативы принудительно обрабатывать события, находящиеся в очереди, следующим образом:

while gtk.events_pending():
    gtk.main_iteration_do(True)
2 голосов
/ 05 декабря 2011

В коде происходит то, что пока выполняется do_something_that_takes_a_while, никакие события не обрабатываются. Одним из способов решения этой проблемы является принудительная обработка событий в некоторой точке внутри этого метода:

--- code.py 2011-12-05 10:32:53.000000000 +0100
+++ code.py.bak 2011-12-05 10:27:22.000000000 +0100
@@ -95,8 +95,6 @@
         timeout = 15
         while timeout != 0:
             self.set('l1','%s' % timeout)
-            while gtk.events_pending():
-                gtk.main_iteration()
             wait(1)
             timeout -= 1
             print timeout
...