2010-07-08 59 views
1

PyGTK窗口在我的PyGTK应用程序中,我要求用户找到一个文件,以便可以对其执行操作。应用程序询问用户该文件,并将该文件名传递给必要的方法。不幸的是,当在该对话框上调用gtk.dispose()方法时,它只是在那里挂起,直到调用完成文件IO的方法。我甚至尝试将文件操作放在另一个线程中,但没有任何效果。PyGTK窗口不告诉

我缩进的目的是让程序显示一个对话框给用户,通知他们他们选择进行操作的文件正在发生。在当前的实施中,在处置gtk.FileChooserDialog之后对话出现

下面是我的代码:

def performFileManipulation(self, widget, data=None): 
     # Create the file chooser dialog: 
     dialog = gtk.FileChooserDialog("Open..", None, gtk.FILE_CHOOSER_ACTION_OPEN, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) 
     dialog.set_default_response(gtk.RESPONSE_OK) 

     # Display the file selector and obtain the response back 
     response = dialog.run() 

     # If the user selected a file, then get the filename: 
     if response == gtk.RESPONSE_OK: 
      dataLocation = dialog.get_filename() 

     # If the file was not chosen, then just close the window: 
     else: 
      print "Closed, no files selected" # Just for now 

     ########## Problem Area ########## 
     # The dialog is told to get destroyed, however, it hangs here in an 
     # unresponsive state until the the file-manipulations performed in a new thread 
     # below are completed. Then, the status dialog (declared below) is displayed. 
     dialog.destroy() # Close the dialog. 

     ## Show a dialog informing the user that the file manipulation is taking place: 
     statusDialog = gtk.Dialog("Performing File Operations...", parent=None, flags=0, buttons=None) 
     statusLabel = gtk.Label("Performing File Operations.\nPlease wait...") 
     statusLabel.set_justify(gtk.JUSTIFY_CENTER) 
     statusLabel.show() 
     statusDialog.vbox.pack_start(statusLabel, True, True, 0) 
     statusDialog.set_default_size(350, 150) 
     statusDialog.show() 

     # Create the thread to perform the file conversion: 
     errorBucket = Queue.Queue()    # Make a bucket to catch all errors that may occur: 
     theFileOperationThread = doStuffToTheFile(dataLocation, errorBucket)  # Declare the thread object. 

     ## Perform the file operations: 
     theFileOperationThread.start()   # Begin the thread 

     # Check on the thread. See if it's still running: 
     while True: 
      theFileOperationThread.join(0.1) 
      if theFileOperationThread.isAlive(): 
       continue 
      else: 
       break 

     # Check if there was an error in the bucket: 
     try: 
      errorFound = errorBucket.get(False) 

     # If no errors were found, then the copy was successful! 
     except Queue.Empty: 
      pass 

     # There was an error in the bucket! Alert the user 
     else: 
      print errorFound 

     statusDialog.destroy() 

请注意,此代码尚未完成,例如,它并没有正确处理用户不选择一个文件,并取消该操作。

编辑:经过进一步调查,似乎是PyGTK的线程问题。问题发生在while True循环中。我用time.sleep(15)替换了该代码,并且类似地,文件选择对话框将暂停。这是非常奇怪的行为,并且所有内容都应该在不同的线程中运行。我想现在的问题是要找出如何将文件选择对话框放在它自己的线程中。

回答

1

混合线程和GTK应用程序(从我记得)往往会产生奇怪的结果。

问题是,即使您调用gtk.dispose,您可能会直接调用方法,这会阻止gtk.mainloop的下一次迭代。

你需要做的是创建另一个函数来进行文件处理,并调用它从回调功能可按:

def doFileStuff(filename): 
    with open(filename, 'r') as f: 
     for line in f: 
      #do something 
    return False # On success 

,然后更改此功能:

def performFileManipulation(self, widget, data=None): 
     # Create the file chooser dialog: 
     dialog = gtk.FileChooserDialog("Open..", 
             None, 
             gtk.FILE_CHOOSER_ACTION_OPEN, 
             (gtk.STOCK_CANCEL, 
             gtk.RESPONSE_CANCEL, 
             gtk.STOCK_OPEN, gtk.RESPONSE_OK)) 
     dialog.set_default_response(gtk.RESPONSE_OK) 

     # Display the file selector and obtain the response back 
     response = dialog.run() 

     # If the user selected a file, then get the filename: 
     if response == gtk.RESPONSE_OK: 
      dataLocation = dialog.get_filename() 

     # If the file was not chosen, then just close the window: 
     else: 
      print "Closed, no files selected" # Just for now 

     # You'll need to import gobject 
     gobject.timeout_add(100, doFileStuff, dataLocation) 

这至少应该让你关闭对话框,我想它会在后台启动文件处理的东西。如果没有,它至少会给你一个地方来启动你的新线程。

HTH

+0

只要有机会,我会尽快解决。 – Phanto 2010-07-08 19:52:47

+0

我正在使用'gobject.timeout_add()'方法的混合,以及ptomato建议删除线程的方法。这使得弹出显示。但是,当只使用一个简单的回调函数时,我怎么知道'doFileStuff()'方法处理完成? 'gobject.timeout_add()'方法返回一个事件源的整数ID。 'gobject.signal_query()'方法会这样做吗? – Phanto 2010-07-09 13:10:50

+0

我认为是这样的:http://pygtk.org/pygtk2reference/gobject-functions.html#function-gobject--signal-query2表示元组将包含'信号回调函数返回的GType。如果回调尚未完成,我认为它将返回无(或GType等效)。 – 2010-07-09 13:56:21

2

有可能没有必要在一个单独的线程执行的文件操作,因为你没有真正做任何事情在这个线程,而文件操作运行 - 只是忙等待。这让我想起为什么代码无法工作:GUI更新在GTK主循环内处理。但是在等待文件线程结束的整个过程中,GTK主循环都不会执行,因为它会一直等待您的performFileManipulation函数结束。

你需要做的是在你的while True循环中执行GTK主循环的迭代。这看起来是这样的:

while True: 
    theFileOperationThread.join(0.1) 
    if theFileOperationThread.isAlive(): 
     while gtk.events_pending(): 
      gtk.main_iteration(block=False) 
    else: 
     break 

但同样,我认为只是在做文件操作在此线程,它似乎是多余的启动另一个线程,然后什么也不做,而它的运行。

+0

您建议删除该线程,并使用Wayne建议的'gobject.timeout_add()'来纠正该问题。谢谢。 – Phanto 2010-07-09 13:12:06

+0

我不认为你需要超时 - GObject中的超时只是运行另一个线程的另一种方式。你可以在这个线程中调用你的文件操作函数,并确保在文件操作过程中经常调用'gtk.events_pending()'和'gtk.main_iteration()'对。 – ptomato 2010-07-09 13:37:56

+0

如果这是不可能的,那么在这种情况下,空闲函数会比超时更好。 – ptomato 2010-07-09 13:38:19