PyGTK 窗口在被告知时不隐藏

发布于 2024-09-08 19:36:52 字数 3070 浏览 6 评论 0原文

在我的 PyGTK 应用程序中,我要求用户查找一个文件,以便可以对其执行操作。应用程序向用户请求文件,并将该文件名转发给必要的方法。不幸的是,当在该对话框上调用 gtk.dispose() 方法时,它只是挂在那里,直到调用执行文件 IO 的方法完成为止。我什至尝试将文件操作放在另一个线程中,但这没有任何效果。

我的缩进目的是让程序向用户显示一个对话框,通知他们正在选择要操作的文件。在当前实现中,对话框在 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) 替换了该代码,同样,文件选择对话框将暂停。这是非常奇怪的行为,所有内容都应该在不同的线程内运行。我想现在的问题是找出如何将“文件选择”对话框放置在它自己的线程中。

In my PyGTK application, I am asking a user to find a file so that operations can be performed on it. The application asks the user for the file, and relays that filename to the necessary methods. Unfortunately, when calling the gtk.dispose() method on that dialog, it just hangs there until the method being called upon to perform the file-IO is complete. I have even tried placing the file manipulations inside of another thread, but that did not have any effect.

My indented purpose is to have the program display a dialog box to the user informing them that the file they selected for manipulation is taking place. With the current implementation, the dialog appears after the gtk.FileChooserDialog is disposed.

Below is my code:

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()

Please note that this code is not yet completed, for instance, it does not yet properly handle the user not selecting a file and canceling the operation.

EDIT: Upon further investigation, there appears to be a threading issue with PyGTK. The problem is occurring in the while True loop. I replaced that code with a time.sleep(15), and similarly, the file select dialog will pause. This is quite odd behavior, and everything should operate inside of a different thread. I guess the question now is to find out how to place the File Selection dialog inside of it's own thread.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

娇女薄笑 2024-09-15 19:36:52

可能不需要在单独的线程中执行文件操作,因为当文件操作正在运行时,您实际上并没有在此线程中执行任何操作 - 只是忙于等待。这让我明白了为什么代码不起作用: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

但同样,我会考虑只在这个线程中执行文件操作,启动另一个线程然后在运行时不执行任何操作似乎是多余的。

There's probably no need to perform the file operations in a separate thread, since you're not really doing anything in this thread while the file operations are running -- just busy-waiting. And that brings me to why the code doesn't work: GUI updates are processed within the GTK main loop. But the whole time while you're waiting for the file thread to finish, the GTK main loop isn't executing, because it's stuck waiting for your performFileManipulation function to end.

What you need to do is perform iterations of the GTK main loop during your while True loop. That looks like this:

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

But again, I would consider just doing the file operations in this thread, it seems redundant to start another thread and then do nothing while it's running.

許願樹丅啲祈禱 2024-09-15 19:36:52

混合线程和 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)

这至少应该让您关闭对话框,我认为它将在背景。如果没有,它至少会给你一个启动新线程的地方。

华泰

Mixing threads and GTK apps (from what I recall) tends to produce weird results.

The problem is that even though you call gtk.dispose, you're probably calling the methods directly, which blocks the next iteration of gtk.mainloop.

What you need to do is create another function to do the file processing and call it from a callback funciton:

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

And then change this function:

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)

That should at least let you close the dialog, and I think it will launch the file processing stuff in the background. If not it will at least give you somewhere to launch your new thread from.

HTH

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文