pygtk中处理主界面与后台连接的方法

来源:互联网 发布:上海口腔科排名 知乎 编辑:程序博客网 时间:2024/06/01 09:45

   这几日学着用pygtk做了一个下载歌曲的小工具,但在实际完成过程中产生了一个让我困扰的问题,pygtk并不像java一样可以将实时产生的数据返回给主界面的progressbar widget,于是造成的结果就是,只要开始下载,主界面就变为“未反应”但实际上下载已经开始。在google无数次后终于找到了一个凑合的解决方法 尽管不是很完美,但基本上可以解决问题。现在贴出来,供大家了解一下。


You have created a progress bar inside a window, then you start running a loop that does some work:

    while work_left:
        ...do something...
        progressbar.set_fraction(...)

You will notice that the window doesn't evenshow up, or if it does the progress bar stays frozen until the end ofthe task. The explanation is simple: gtk is event driven, and you arestealing control away from the gtk main loop, thus preventing it fromprocessing normal GUI update events.

The simplest solution consists on temporarily giving control back to gtk every time the progress is changed:

    while work_left:
        ...do something...
        progressbar.set_fraction(...)
        while gtk.events_pending():
            gtk.main_iteration()

Notice that with this solution, the usercannot quit the application (gtk.main_quit would not work because ofnew loop [gtk.main_iteration()]) until your heavy_work is done.

Another solution consists on using gtk idlefunctions, which are called by the gtk main loop whenever it hasnothing to do. Therefore, gtk is in control, and the idle function hasto do a bit of work. It should return True if there's more work to bedone, otherwise False.

The best solution (it has no drawbacks) waspointed out by James Henstridge. It is taking advantage of python'sgenerators as idle functions, to make python automatically preserve thestate for us. It goes like this:

    def my_task(data):
        ...some work...
        while heavy_work_needed:
            ...do heavy work here...
            progress_label.set_text(data) # here we update parts of UI
            # there's more work, return True
            yield True
        # no more work, return False
        yield False

   def on_start_my_task_button_click(data):
        task = my_task(data)
        gobject.idle_add(task.next)

The 'while' above is just an example. Theonly rules are that it should yield True after doing a bit of work andthere's more work to do, and it must yield False when the task is done.

More on generators:

Generators are objects that are defined asfunctions, and when called produce iterators that return values definedby the body of the function, specifically yield statements.

The neat thing about generators are not theiterators themselves but the fact that a function's state is completelyfrozen and restored between one call to the iterator's next() and thefollowing one. This is just the right thing we need to turn ourfunctions into pseudo-threads, without actually incurring the wrath ofthe gods of software.
More:
http://www.gnome.org/~gjc/gtasklet/gtasklets.html
主要的办法就是使用gobject的idle_add

更好的办法也找到了,就是lazybones前辈的gmbox的解决方法,感觉他的更好一点,有兴趣的可以去看看他的gmbox代码 地址是http://gmbox.googlecode.com/files/gmbox-0.2.tar.gz 有兴趣的可以下载下来看看