Search code examples
pythonpython-3.xtreeviewgtkgtk3

GTK Python Update Treeview


I have a GTK3 GUI called by Python 3.8 code. A treeview is added on the GUI. I want to update the treeview in every 1 seconds, but it uses too much CPU power and crashes after abut ten seconds. When I use smaller data. When bigger data (250 rows) is used and it gives error immediately:

Backend terminated or disconnected. Use 'Stop/Restart' to restart.

What is the solution to update the data efficiently?

Code example:

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

builder = Gtk.Builder()
builder.add_from_file('example.glade')
builder.get_objects()
window1 = builder.get_object('window1')

class Signals:
    def on_window1_destroy(self, widget):
        Gtk.main_quit()

def data_add(thread1):
    while True:
    starttime1 = time.time()
    time.sleep(1 - ((time.time() - starttime1) % 1))

    dict1 = {1: {"name": "data1", "content": "data2", "date": "data3"}, 
             2: {"name": "data4", "content": "data5", "date": "data6"},
             3: {"name": "data7", "content": "data8", "date": "data9"},
             .
             .
             .
             250: {"name": "datax", "content": "datay", "date": "dataz"}}
    .
    .
    # Dictionary data converted to list data.
    .
    .
    global initial_run
    if initial_run == 1:
        treeview1 = Gtk.TreeView()
        liststore1 = Gtk.ListStore(str, str, str, int, float)
        treeview1.set_model(liststore1)

    for i in range(0, 250):
        liststore1.append([list_data1[i], list_data2[i], list_data3[i], list_data4[i]])
            
    if initial_run == 1:
    for i, column in enumerate(process_columns):
        cell = Gtk.CellRendererText()
        col = Gtk.TreeViewColumn(column, cell, text=i)
        treeview1.append_column(col)

    treeview1.show()
    initial_run=0


thrd = threading.Thread(target=data_add, args = ("thread1", ), daemon=True)
thrd.start()

builder.connect_signals(Signals())
window1.show_all()
Gtk.main()

Solution

  • The reason why you're consuming so much CPU, is because you've implemented a busy loop which repeatedly adds (not updates) 250 rows to your Gtk.TreeView. Another problem is that you're calling Gtk API from a different thread, which is not allowed since GTK explicitly isn't thread-safe.

    To periodically execute a function (or callback, really) on the main thread, you can use API such as GLib.timeout_add_seconds(). If you reallly have work that needs to be done on a different thread, you should perform your operations in the thread and call GLib.idle_add() to update the treeview with the results.

    As far as the updating of the treeview itself goes: for each row in your dataset, you'll first have to find an existing entry in the liststore and update that, rather than trying to continuously create a new one.