Threads

For things that take a long time...


Looping is great for regularly updating the GUI, but if you want to call a function that might take a long time (such as downloading a file) you need to use a thread.

Running your functions in threads allows the main GUI loop to keep running, so that the GUI won't hang.

NB. Threads don't always work nicely with GUIs, so your thread mustn't try to change the GUI, instead you will need to put any GUI updates in a Queue (see below).

Threading


def uploadFile(filename):
    # this would upload the file to a server
    pass

def uploader(btn=None):
    filename = app.getEntry("file")
    if filename != "":
        app.setLabel("uploadStatus", "Uploading " + filename)

        # call uploadFile(), with the contents of the "file" entry box
        # when uploadFile() completes, its return value will be passed to uploadComplete()
        app.threadCallback(uploadFile, uploadComplete, filename)

def uploadComplete(success):
    if success:
        message = "Upload complete"
    else:
        message = "Upload failed"

    app.queueFunction(app.setLabel, "uploadStatus", message)

app.addLabel("uploadStatus", "No uploads")
app.addFileEntry("file")
app.addButton("UPLOAD", uploader)

Queueing


You mustn't try to update the GUI directly from a thread.
Instead, you should add all your updates to appJar's update queue, and let appJar update the GUI.

downloadCount = 0

def downloader():
    global downloadCount
    # it's fine to put loops in threads
    for i in range(5):
        # update the GUI through the GUI queue
        app.queueFunction(app.setLabel, "l1", "Starting download " + str(downloadCount))
        # this takes a long time
        downloadFile("file" + str(downloadCount) + ".dat")
        # update the GUI through the GUI queue
        app.queueFunction(app.setLabel, "l1", "Finished download " + str(downloadCount))
        # it's fine to put sleeps in threads
        time.sleep(1)

# put the downloader function in its own thread
app.thread(downloader)