在长时间运行的过程中阻止pygtk GUI锁定 [英] Stop pygtk GUI from locking up during long-running process

查看:59
本文介绍了在长时间运行的过程中阻止pygtk GUI锁定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个过程需要一段时间(可能需要一两分钟)才能完成.当我从pygtk GUI调用此窗口时,大约10秒钟后,窗口将锁定(变暗并阻止用户操作).

I have a process that will take a while (maybe a minute or two) to complete. When I call this from my pygtk GUI the window locks up (darkens and prevents user action) after about 10 seconds.

我想阻止这种情况的发生,但是我不确定如何发生.我以为多线程将是答案,但是它似乎没有用.我尝试了两种在网上找到的不同方法.首先,我修改了此常见问题解答以长期运行的功能.其次,我尝试直接使用threading.Thread,就像在此答案中一样,但这也会锁定.

I'd like to stop this from happening, but I'm not sure how. I thought multithreading would be the answer, but it doesn't seem to be working. I've tried two different methods I found online. First, I modified this FAQ to take a long running function. Secondly I tried using threading.Thread directly like in this answer, but that also locks up.

下面是我的两个样本.我是多线程的新手,所以也许这不是我想要的解决方案.我基本上只是想防止GUI锁定,因此我可以使用进度条进行更新,并允许用户使用取消"按钮.

My two samples are below. I'm new to multithreading, so maybe it's not the solution I'm looking for. I'm basically just trying to keep the GUI from locking up so I can update with a progress bar and let the user use a cancel button.

#Sample 1
import threading
import time
import gobject
import gtk

gobject.threads_init()

class MyThread(threading.Thread):
    def __init__(self, label, button):
        super(MyThread, self).__init__()
        self.label = label
        self.button = button
        self.counter = 0
        button.connect("clicked", self.on_button_click)
        self.quit = False

    def update_label(self, counter):
        self.label.set_text("Counter: %i" % counter)
        time.sleep(20)
        return False

    def on_button_click(self, widget):
        self.counter += 1
        gobject.idle_add(self.update_label, self.counter)

window = gtk.Window()
label = gtk.Label()
box = gtk.VBox()
button = gtk.Button("Test")
box.pack_start(label)
box.pack_start(button)
window.add(box)
window.show_all()
window.connect("destroy", lambda _: gtk.main_quit())
thread = MyThread(label, button)
thread.start()

gtk.main()
thread.quit = True

#####################################
#Sample 2

from threading import Thread
import time
import gobject
import gtk

class Test():
    def __init__(self):
        self.counter = 0
        self.label = gtk.Label()
        button = gtk.Button("Test")

        window = gtk.Window()
        box = gtk.VBox()
        box.pack_start(self.label)
        box.pack_start(button)
        window.add(box)

        window.connect("destroy", lambda _: gtk.main_quit())
        button.connect("clicked", self.on_button_click)
        window.show_all()

    def update_label(self, counter):
        self.label.set_text("Counter: %i" % counter)
        time.sleep(20)
        return False

    def on_button_click(self, widget):
        self.counter += 1
        thread = Thread(target=self.update_label, args=(self.counter,))
        thread.start()
        while thread.is_alive():
            pass
        thread.stop()

test = Test()
gtk.main()

推荐答案

请在下面找到适合我的第二个示例的修改版本:

Please find below a modified version of the second example that works for me:

import threading
import time
import gtk, gobject, glib

gobject.threads_init()

class Test():
    def __init__(self):
        self.counter = 0
        self.label = gtk.Label()
        self.progress_bar = gtk.ProgressBar()
        self.progress_bar_lock = threading.Lock()
        button = gtk.Button("Test")

        window = gtk.Window()

        box = gtk.VBox()
        box.pack_start(self.label)
        box.pack_start(self.progress_bar)
        box.pack_start(button)
        window.add(box)

        window.connect("destroy", lambda _: gtk.main_quit())
        button.connect("clicked", self.on_button_click)
        window.show_all()

    def update_label(self, counter):
        self.label.set_text("Thread started (counter: {0})"
                            .format(counter))
        time.sleep(5)
        self.label.set_text("Thread finished (counter: {0})"
                            .format(counter))
        return False

    def pulse_progress_bar(self):
        print threading.active_count()
        if threading.active_count() > 1:
            self.progress_bar.pulse()
            return True

        self.progress_bar.set_fraction(0.0)
        self.progress_bar_lock.release()
        return False

    def on_button_click(self, widget):
        self.counter += 1
        thread = threading.Thread(target=self.update_label,
                                  args=(self.counter,))
        thread.start()

        if self.progress_bar_lock.acquire(False):
            glib.timeout_add(250, self.pulse_progress_bar)


if __name__ == '__main__':
    test = Test()
    gtk.main()

所做的更改是:

  • 避免在回调中等待线程完成以保留主循环处理事件.
  • 添加了进度条以在执行线程时显示.
  • 使用glib.timeout_add安排在执行某些线程时使进度条产生脉冲的回调.这与轮询线程具有相同的效果,但优点是主循环仍可响应其他事件.
  • 使用threading.Lock来证明要安排多次回调,而无论单击按钮多少次.
  • 添加了本示例中缺少的gobject.threads_init(在上一个示例中没有).
  • Avoid waiting in the callback for the thread to finish to keep the main loop processing events.
  • Added progress bar to display when a thread is being executed.
  • Used glib.timeout_add to schedule a callback that pulses the progress bar when some thread is being executed. This has the same effect as polling the thread, but with the advantage that the the main loop is still responsive to other events.
  • Used threading.Lock to provent the callback to be scheduled more than once, regardless of how many times the button is clicked.
  • Added gobject.threads_init that was missing in this example (not in the previous one).

现在,当单击按钮时,只要线程正在运行,您将看到如何单击标签和进度条脉动.

Now, when clicking on the button, you'll see how the label is clicked and the progress bar pulsed as long as a thread is running.

这篇关于在长时间运行的过程中阻止pygtk GUI锁定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆