2011-02-01 22 views
3

我想獲得關於如何在Python的PyGTK中實現進度條的最佳實踐的其他人的意見反饋。Python的PyGTK中進度條的最佳實踐

進度條代表的工作在計算上非常重要。因此,我希望這項工作能夠在一個單獨的過程中完成(從而使操作系統可以在不同的核心上運行它)。我希望能夠開始工作,然後在等待結果的同時繼續使用GUI進行其他任務。

我見過很多人間接提出這個問題,但我還沒有看到任何具體的專家意見。我希望通過提出這個問題,我們將看到一個社區的綜合專業知識。

+0

這是更多的堆棧Overflo一個問題W上。即使你要求最好,最好也可以是主觀的,在這種情況下,你實際上解釋了什麼是最適合你的。 – Ziv 2011-06-01 23:05:42

回答

4

我現在意識到,我沒有足夠的聲望使其成爲社區wiki,所以我希望別人可以將其更改爲wiki狀態。謝謝。

我絕不是一個專家的Python程序員,但我花了一些時間試圖找到一個可接受的解決方案。我希望以下代碼可以作爲本次討論的出發點。

import gobject 
import pygtk 
pygtk.require('2.0') 
import gtk 
import multiprocessing 
import threading 
import time 

gtk.gdk.threads_init() 

class Listener(gobject.GObject): 
    __gsignals__ = { 
     'updated' : (gobject.SIGNAL_RUN_LAST, 
        gobject.TYPE_NONE, 
        (gobject.TYPE_FLOAT, gobject.TYPE_STRING)), 
     'finished': (gobject.SIGNAL_RUN_LAST, 
        gobject.TYPE_NONE, 
        ()) 
    } 

    def __init__(self, queue): 
     gobject.GObject.__init__(self) 
     self.queue = queue 

    def go(self): 
     print "Listener has started" 
     while True: 
      # Listen for results on the queue and process them accordingly        
      data = self.queue.get() 
      # Check if finished                  
      if data[1]=="finished": 
       print "Listener is finishing." 
      self.emit("finished") 
      return 
      else: 
       self.emit('updated', data[0], data[1]) 

gobject.type_register(Listener) 

class Worker(): 
    def __init__(self, queue): 
     self.queue = queue 

    def go(self): 
     print "The worker has started doing some work (counting from 0 to 9)" 
     for i in range(10): 
     proportion = (float(i+1))/10 
     self.queue.put((proportion, "working...")) 
      time.sleep(0.5) 
     self.queue.put((1.0, "finished")) 
     print "The worker has finished." 


class Interface: 
    def __init__(self): 
     self.process = None 
     self.progress = gtk.ProgressBar() 
     button = gtk.Button("Go!") 
     button.connect("clicked", self.go) 
     vbox = gtk.VBox(spacing=5) 
     vbox.pack_start(self.progress) 
     vbox.pack_start(button) 
     vbox.show_all() 
     self.frame = vbox 

    def main(self): 
     window = gtk.Window(gtk.WINDOW_TOPLEVEL) 
     window.set_border_width(10) 
     window.add(self.frame) 
     window.show() 
     window.connect("destroy", self.destroy) 

     gtk.main() 

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


    def callbackDisplay(self, obj, fraction, text, data=None): 
     self.progress.set_fraction(fraction) 
     self.progress.set_text(text) 

    def callbackFinished(self, obj, data=None): 
     if self.process==None: 
      raise RuntimeError("No worker process started") 
     print "all done; joining worker process" 
     self.process.join() 
     self.process = None 

     self.progress.set_fraction(1.0) 
     self.progress.set_text("done") 

    def go(self, widget, data=None): 
     if self.process!=None: 
      return 

     print "Creating shared Queue" 
     queue = multiprocessing.Queue() 

     print "Creating Worker" 
     worker = Worker(queue) 

     print "Creating Listener" 
     listener = Listener(queue) 
     listener.connect("updated",self.callbackDisplay) 
     listener.connect("finished",self.callbackFinished) 

     print "Starting Worker" 
     self.process = multiprocessing.Process(target=worker.go, args=()) 
     self.process.start() 

     print "Starting Listener" 
     thread = threading.Thread(target=listener.go, args=()) 
     thread.start() 

if __name__ == '__main__': 
    gui = Interface() 
    gui.main() 

一些引用我發現有用的是:

+0

Eep。如果你使用PyGTK的線程,你需要非常小心。使用[GUI鎖定](http://developer.gnome.org/pygtk/stable/gdk-functions.html#function-gdk-lock)即開始主循環。在'gtk.gdk.lock:'裏面。導致UI變化的任何呼叫,包括信號發射,都需要在這樣的一個塊中。在開始主循環之前,你需要調用'gtk.gdk.threads_init()'。 – detly 2011-06-02 01:24:15

+0

它工作得非常好,只是說一些縮進缺少4行,但是很棒的工作! – Victor 2017-07-20 16:22:57