How to implement the abolition of actions?
-
21-12-2019 - |
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.
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...