Streams in Gtk python
So I am busy writing an application that needs to check for updates from a website after a certain amount of time, I am using python with Gtk +3
main.py file
class Gui:
...
def on_update_click():
update()
app=Gui()
Gtk.main()
update.py file
def update():
#check site for updates
time.sleep(21600) #check again in 6hrs
I suspect I will have to use streams. my thinking:
Gtk.main () starts the main thread.
when the user clicks the update button, update () runs in the background. #thread 2
Am I correct or am I missing something?
EDIT: Ok, the
on_update_click function:
Thread(target=update).start().
K, the computer no longer freezes: D
so what happens now, only when I close Gtk.main (), only the update thread is started. It's nice that it keeps updating when the UI is closed, but I would also like to start it when the UI is enabled.
source to share
So finally I managed to get it to work. I needed to say:
from gi.repository import Gtk,GObject
GObject.threads_init()
Class Gui:
.....
......
def on_update_click():
Thread(target=update).start()
First I used:
thread.start_new_thread(update())
in the on_update_click function. As my JFSebastian already mentioned, this was incorrect, as it would bring up this thread right away. This froze my entire computer.
Then I just added:
Thread(target=update).start()
The on_update_clicked function only worked after the main thread Gtk.main () was closed. This way the threads were not started at the same time.
adding: GObject.threads_init ()
this allowed threads to run the python interpreter sequentially: Themes in Gtk !
source to share
thread.start_new_thread(update())
wrong. It calls update()
immediately on the main thread, and you don't have to use the module thread
directly; use a module instead threading
.
You can call threading.current_thread()
to find out which thread is executing update()
.
To keep your code simpler, you can run all gtk code on the main thread and use blocking operations to fetch web pages and run them on a background thread.
Based on an extended example from the GTK + 3 tutorial :
#!/usr/bin/python
import threading
import urllib2
from Queue import Queue
from gi.repository import Gtk, GObject
UPDATE_TIMEOUT = .1 # in seconds
_lock = threading.Lock()
def info(*args):
with _lock:
print("%s %s" % (threading.current_thread(), " ".join(map(str, args))))
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Hello World")
self.button = Gtk.Button(label="Click Here")
self.button.connect("clicked", self.on_button_clicked)
self.add(self.button)
self.updater = Updater()
self._update_id = None
self.update()
def on_button_clicked(self, widget):
info('button_clicked')
self.update()
def update(self):
if self._update_id is not None:
GObject.source_remove(self._update_id)
self.updater.add_update(self.done_updating) # returns immediately
# call in UPDATE_TIMEOUT seconds
self._update_id = GObject.timeout_add(
int(UPDATE_TIMEOUT*1000), self.update)
def done_updating(self, task_id):
info('done updating', task_id)
self.button.set_label("done updating %s" % task_id)
class Updater:
def __init__(self):
self._task_id = 0
self._queue = Queue(maxsize=100) #NOTE: GUI blocks if queue is full
for _ in range(9):
t = threading.Thread(target=self._work)
t.daemon = True
t.start()
def _work(self):
# executed in background thread
opener = urllib2.build_opener()
for task_id, done, args in iter(self._queue.get, None):
info('received task', task_id)
try: # do something blocking e.g., urlopen()
data = opener.open('http://localhost:5001').read()
except IOError:
pass # ignore errors
# signal task completion; run done() in the main thread
GObject.idle_add(done, *((task_id,) + args))
def add_update(self, callback, *args):
# executed in the main thread
self._task_id += 1
info('sending task ', self._task_id)
self._queue.put((self._task_id, callback, args))
GObject.threads_init() # init threads?
win = MyWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
Note. GObject.idle_add()
is the only gtk-related function called from different threads.
See also Multithreaded GTK Applications - Part 1: Misconceptions .
source to share
Threading is the first way to solve the problem. You can create a thread and run a long term blocking function inside that thread (and your GUI won't hang up).
Another way is to use an asynchronous network for example. using python-gio (GObject-IO) or another library that has the ability to work with the main GLib loop ( as it does with Twisted ). This approach is slightly different and uses non-blocking socket operations. Your main loop will make a callback when data from the socket (the site you are polling from) is readable. Unfortunately GIO does not have a high level HTTP API, so you can use GSocketClient
and manually create the HTTP request structure.
source to share