Question

I write some simple program with Python and PyGObject. I wanted her to inform the user about the progress through the ProgressBar. I googled that this process should be a separate thread, otherwise the interface hold on, and now have some like this for tests:

import time
import threading
from gi.repository import Gtk, GObject

GObject.threads_init()

def tread_function():
    progress.set_fraction(0)
    time.sleep(5)
    progress.set_fraction(0.25)
    time.sleep(5)
    progress.set_fraction(0.5)
    time.sleep(5)
    progress.set_fraction(0.75)
    time.sleep(5)
    progress.set_fraction(1)


def clickOk(*args):
    t = threading.Thread(target=tread_function)
    t.start()

def clickCancel(*args):
    pass

buttonOk = Gtk.Button("Start Count")
buttonOk.connect("clicked", clickOk)

buttonCancel = Gtk.Button("Cancel Count")
buttonCancel.connect("clicked", clickCancel)

progress = Gtk.ProgressBar()
progress.set_show_text(True)

vBox = Gtk.VBox()
vBox.pack_start(buttonOk, True, True, 10)
vBox.pack_start(buttonCancel, True, True, 10)
vBox.pack_start(progress, True, True, 10)

window = Gtk.Window()
window.connect('destroy', Gtk.main_quit)
window.add(vBox)
window.show_all()

Gtk.main()

Now when the interface does not hold on, I would like to give a chance user to stop the work to its full completion, if he made ​​a mistake in settings. But I can not googled, or find in documentation how to kill a thread before its complete execution.

Was it helpful?

Solution

There is no trivial way to kill a thread in python. To get around this you need to build in your own hooks that will trigger early thread exits. A good way to do this is to use Event, which is a thread-safe trigger that can be set.

Before you do that though, you may wish to wrap up your code in some classes. Writing GUIs without classes will only cause you pain in the long term.

from threading import Event,Thread


class FakeClass(object):
    def __init__(self):
        self.progress = Gtk.ProgressBar()
        self.progress.set_show_text(True)
        self.buttonOk = Gtk.Button("Start Count")
        self.buttonOk.connect("clicked", self.clickOk)
        self.buttonCancel = Gtk.Button("Cancel Count")
        self.buttonCancel.connect("clicked", self.clickCancel)

        #create an event to trigger in your thread
        self.trigger = Event() 
        self.t = None

        #Other GTK stuff here...

    def tread_function(self):
        progress_fraction = 0.0

        #keep looping while the trigger is not set and the 
        #progress is not > 1.0
        while not self.trigger.is_set() and progress <= 1.0:
            progress.set_fraction(progress_fraction)
            time.sleep(1)
            progress_fraction += 0.1

    def clickOk(self, *args):
        # reset the trigger
        self.trigger.clear()
        #launch the thread
        self.t = threading.Thread(target=self.tread_function)
        self.t.start()

    def clickCancel(self, *args):
        # set the trigger (interrupting the thread)
        self.trigger.set()
        # join the thread so it is not left hanging
        if not self.t is None:
            self.t.join()


    # More other GTK stuff here...
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top