Search code examples
pythonuser-interfacetkintertreeviewttk

Treeview - call to set column text before long function ignored


I'm new to GUI programming with tkinter and python 3.

What it's supposed to do:

My application extracts DOIs from medical journal articles. PDFs are displayed using a ttk.Treeview. Double-clicking on a file starts a text extraction function, which can take up to 5 seconds, depending on the size of the PDF. The status column displays "processing ..." before the function is called, and "complete" after.

This is my poor man's version of a progress bar, since I haven't learned those or threading yet.

What actually happens:

Double-clicking the file starts the function, and then sets the status column to "complete". It never displays "processing".

What am I missing here?

Example

This creates a ttk.Treeview and loads the current directory. Double-clicking any file should set the status, wait 4 seconds (to simulate the lengthy function), then set the status again.

import os, time
import tkinter as tk
from tkinter import ttk

class DirBrowser(tk.Frame):

    def __init__(self, parent):
        super().__init__(parent)
        self.parent = parent
        self.path = os.getcwd()
        self.setup_tree()


    def setup_tree(self):
        self.tree = ttk.Treeview(self, columns=('status'))
        self.tree.pack(expand=True, fill=tk.BOTH)

        self.tree.heading("#0", text="Directory", anchor='w')
        self.tree.heading('status', text='Status', anchor='w')

        self.tree.bind('<Double-Button-1>', self.on_dblclick)

        for directory, subdir_list, file_list in os.walk(self.path):
            node = self.tree.insert('', 'end', text=directory)

            for file in file_list: 
                self.tree.insert(node, 'end', text=file)


    def on_dblclick(self, event):
        selected = self.tree.selection()[0]

        # set status column to 'processing'
        self.tree.set(selected, 'status', 'processing ...')

        # simulate a time-consuming function
        # the real program extracts text from a PDF here
        time.sleep(4)

        # set status column to 'complete'
        self.tree.set(selected, 'status', 'complete')


if __name__ == '__main__':
    master = tk.Tk()
    tree = DirBrowser(master).pack(fill=tk.BOTH, expand=True)
    master.mainloop()

Solution

  • You need to update the interface after you change the TreeView text as follows

        def on_dblclick(self, event):
                selected = self.tree.selection()[0]
    
                # set status column to 'processing'
                self.tree.set(selected, 'status', 'processing ...')
    
                # Update (like a single step of mainloop)
                self.parent.update()  # <-- ADD
    
                # simulate a time-consuming function
                # the real program extracts text from a PDF here
                time.sleep(4)
    
                # set status column to 'complete'
                self.tree.set(selected, 'status', 'complete')