PyGTK窗口未按指示隐藏
在我的PyGTK应用程序中,我让用户找到一个文件,以便对其进行操作。程序会要求用户选择文件,然后把文件名传递给需要的功能。不过,当我调用gtk.dispose()
方法关闭对话框时,它会一直卡在那里,直到文件操作完成。我甚至尝试把文件操作放在另一个线程里,但也没有什么效果。
我希望程序能显示一个对话框,告诉用户他们选择的文件正在被处理。但现在的实现是,对话框在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)
,结果文件选择对话框也会暂停。这种行为很奇怪,所有操作应该在不同的线程中进行。我现在的问题是,如何把文件选择对话框放在自己的线程里。
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
不过我还是建议你直接在这个线程里做文件操作,启动另一个线程然后什么都不做,感觉有点多余。
把线程和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)
这样至少可以让你关闭对话框,我觉得它会在后台启动文件处理的工作。如果没有,它至少会给你一个地方来启动你的新线程。
希望这对你有帮助。