2016-02-29 28 views
0

即使我沒有給出gtkMainLoop.start()函數調用,下面的代碼在聲明og gtkLoopTHread本身後也會受到衝擊。 我想在後臺運行計時器並在該UI中執行一些操作,並在計時器達到0時銷燬UI。PyGtk:在單獨的線程中運行gtk.main()循環

代碼

def createCountDown(maxSec): 
    while maxSec > 0: 
    print maxSec; 
    maxSec = maxSec - 1; 

    gtk.main_quit(); 
    return; 

maxSec = 5; 
gtkLoopThread = threading.Thread(group=None, target=gtk.main, name=None, args=(), kwargs={}); 
print "After gtkThread declaration" 
myThread = threading.Thread(group=None, target=createCountDown, name=None, args=(maxSec), kwargs={}); 
gtkLoopThread.start(); 
myThread.start(); 

預期輸出:

After gtkThread declaration 
5 
4 
3 
2 
1 

當前的行爲: 線 'gtkThread聲明後' 因爲gtkLoopThread打印是沒有看到立即初始化後開始gtkLoopThread變量e

+0

不,你不能在其他GTK +代碼的不同線程上運行'gtk.main()'。你需要在一個單獨的線程上運行你的其他東西。你也不能在單獨的線程上運行'gtk.main_quit()';您需要使用'glib.idle_add()'將一個函數排隊以在GTK +線程上運行。抱歉。 – andlabs

+0

如果你只是想要一個計時器,你也可以使用'glib.timeout_add()'。 – elya5

回答

3

有幾個問題妨礙您的代碼正常運行。

首先,您在程序開始時錯過了對gobject.threads_init()(在import gobject之後)的調用。這個調用導致PyGTK在進入主循環時釋放GIL。未能調用它將使線程無用。 (在與Python 3最新PyGObject,這是no longer necessary.

第二個問題,而這一次是微不足道的,是你錯誤地構建一個元素的元組用作args參數傳遞給threading.Thread構造 - 它應該是args=(maxSec,),而不是args=(maxSec)

經過上述兩項更改後,您的程序將顯示預期輸出。

最後,as andlabs points outdocumentation confirms,不允許從運行主循環的線程以外的任何線程調用GTK代碼。工作線程可以使用gobject.idle_add來調度要在GUI線程中執行的代碼,而不是調用GTK函數。 (如果GUI線程空閒,它應該是這樣,這會立即發生。)換句話說,您應該用gobject.idle_add(gtk.main_quit)替換gtk.main_quit()。如果or函數帶有參數,請改爲使用gobject.idle_add(lambda: gtk_call_here(...)。儘管在GTK程序中創建多個工作線程是完全合法的,但它們必須保持清除直接調用到GTK中的必須的

此外,根據文檔,運行主循環的線程應該與初始化GTK的線程相同。因此在GUI線程啓動之前,正確的程序不應該爲import gtk(它初始化它)。下面是你的代碼的一個版本,它實現了這個功能:

import threading 

# Event marking the GUI thread as having imported GTK. GTK must not 
# be imported before this event's flag is set. 
gui_ready = threading.Event() 

def run_gui_thread(): 
    import gobject 
    gobject.threads_init() 
    import gtk 
    gui_ready.set() 
    gtk.main() 

gui_thread = threading.Thread(target=run_gui_thread) 
gui_thread.start() 

# wait for the GUI thread to initialize GTK 
gui_ready.wait() 

# it is now safe to import GTK-related stuff 
import gobject, gtk 

def countdown(maxSec): 
    while maxSec > 0: 
     print maxSec 
     maxSec -= 1 

    gobject.idle_add(gtk.main_quit) 

worker = threading.Thread(target=countdown, args=(5,)) 
print 'starting work...' 
worker.start() 

# When both the worker and gui_thread finish, the main thread 
# will exit as well.