Question

I have this code :

def on_btn_login_clicked(self, widget):
    email = self.log_email.get_text()
    passw = self.log_pass.get_text()
    self.lbl_status.set_text("Connecting ...")
    params = urllib.urlencode({'@log_email': email, '@log_pass': passw, '@action': 'login', '@module': 'user'})
    headers = {"Content-type": "application/x-www-form-urlencoded","Accept": "text/plain"}
    conn = httplib.HTTPConnection("website.com")
    self.lbl_status.set_text("Logging in ...")
    conn.request("POST", "/ajax.php", params, headers)
    response = conn.getresponse()
    print response.status
    self.lbl_status.set_text("")
    data = response.read()      
    print data
    conn.close()

The self.lbl_status doesn't change till the request is finished, so it displays nothing due to the last set_text function.

Why is this happening, and how to avoid/fix that?

Was it helpful?

Solution

Below is a working example of a simple downloader for illustration purposes only. You need to use multi-threading if you want your GUI to be responsive and not freeze while you do some long running or blocking operation. I put this example together based on this stack overflow question and this excellent article Using threads in PyGTK. The default url an Ubuntu iso will take a while to download and should provide a good demonstration . You can enter any url you want when prompted it will download and save the file in the current directory.

from threading import Thread
import time
import gtk, gobject, urllib

URL = 'http://releases.ubuntu.com//precise/ubuntu-12.04.1-desktop-i386.iso'

def download(url):
    filename = url.split('/')[-1]
    out = open(filename, 'wb')
    gobject.idle_add(label.set_text, "connecting...")
    f = urllib.urlopen(url)
    buffer = f.read(1024)
    counter = 0
    while buffer:
        counter += len(buffer)
        out.write(buffer)
        msg = "downloaded {0:,} bytes".format(counter)
        gobject.idle_add(label.set_text, msg)
        buffer = f.read(1024)
    out.close()
    gobject.idle_add(label.set_text, "download complete")

def clicked(button):
    url = entry.get_text()
    Thread(target=download, args=(url,)).start()


gtk.gdk.threads_init()
win = gtk.Window()
win.set_default_size(400, 100)
entry = gtk.Entry()
entry.set_text(URL)
label = gtk.Label("Press the button")
button = gtk.Button(label="Download")
button.connect('clicked', clicked)

box = gtk.VBox()
box.pack_start(entry)
box.pack_start(label)
box.pack_start(button)
win.add(box)

win.show_all()

gtk.main()

OTHER TIPS

Gtk doesn't update anything until the main loop runs. That means it first does all its changes and only updates after they're all done. This is because it intends all callbacks to be atomic (finish in a negligible time). A callback should never use a blocking call, because it means the interface will freeze.

There are two possible solutions here. The best is to register a new callback when a response is ready, and return to the main loop. However, this may not be easy. A dirty workaround is to force the main loop to handle pending events before making the blocking call. It will then update the label. You can do this with

while gtk.events_pending ():
    gtk.main_iteration (False)

But as I wrote, not calling any blocking functions from the callback is much cleaner.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top