Python Forum

Full Version: tkinter - update/refresh treeview
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
I've got a treeview widget that is supplied data from an sql database.

I've been trying all day to make it so when I add a row to the database that the treeview instantly updates. I can't even begin to explain what I've tried so far but it's mostly based around trying to re-run def populate_tab_tree from the end of def on_save_button. I've also tried pasting the code into the end of my on_save_button method.

Needless to say, it's failed every time.

Can anyone point me in the right direction please.

Thank you

###### TO DO #######
Simpligy the way buttons are added. 
Scrollbar not working
update treeview when new contact added to database
id row (use rowid? treeview messed up)
edit contact in database (select record, insert into entry box)
delete contact in databse

from tkinter import *
from tkinter.ttk import *
import sqlite3

### Create tkinter window ##
root = Tk()

### Add a Notebook to window ###
notebook = Notebook(root)
notebook.pack(fill="both", expand=1, pady=15)

### Class to add tabs to the notebook. Methods allow to add a Treeview, populate treeview ###
class Tab:
    def __init__(self, tab): = tab = Frame(notebook)"both", expand=1)
        notebook.add(, text=str(tab)) 

    def tab_tree(self, column_names):
        self.column_names = column_names    
        self.treeview_frame = Frame(
        self.treeview_frame.pack(fill="both", expand=1)
        self.tree_scroll = Scrollbar(self.treeview_frame)
        self.tree_scroll.pack(side=RIGHT, fill=Y) 
        self.tab_tree = Treeview(self.treeview_frame, yscrollcommand=self.tree_scroll.set, selectmode="extended") 
        self.tab_tree.pack(fill="both", expand=YES)        
        self.tab_tree['columns'] = column_names
        self.tab_tree.column("#0", width=0, stretch=NO)
        self.tab_tree.heading("#0", text="")
        for name in column_names:
            self.tab_tree.column(name, minwidth=25, width=50) 
            self.tab_tree.heading(name, text=name)                  
    def populate_tab_tree(self, table, columns):
        self.table = table
        self.columns = columns

        conn = sqlite3.connect('Bookkeeping_Database.sqlite3')
        cur = conn.cursor()
        cur.execute("CREATE TABLE IF NOT EXISTS " + self.table + " (" + " TEXT, ".join(self.columns) +" TEXT)")
        cur.execute("SELECT * FROM " + self.table)
        records = cur.fetchall()     

        for row in records:
            self.tab_tree.insert(parent='', index='end', iid=count, text='', values=row)
### Class to create contact tab ###
class Create_contact_tab:
    def __init__ (self, tab_name, new_contact_button_name, column_names):
        self.tab_name = tab_name
        self.new_contact_button_name = new_contact_button_name
        self.tab_name = tab_name 
        self.column_names = column_names

        self.contact_tab = Tab(self.tab_name)
        self.contact_tab.populate_tab_tree(tab_name, column_names)   

        self.new_contact_button = Button(, text=(self.new_contact_button_name), command=self.new_contact_window)
        self.new_contact_button.pack(side=LEFT, padx=10, pady=10) 

        self.edit_contact_button = Button(, text="Edit", command=self.edit_contact_window)
        self.edit_contact_button.pack(side=LEFT, padx=10, pady=10) 

        self.delete_contact_button = Button(, text="Delete")
        self.delete_contact_button.pack(side=LEFT, padx=10, pady=10)
    def new_contact_window(self):
        self.new_contact_window = New_contact_window(self.tab_name) 

    def edit_contact_window(self):
        self.edit_contact_window = Edit_contact_window(self.tab_name)
    def select_record(self):
        selected = self.contact_tab.tab_tree.focus()
        values = self.contact_tab.tab_tree(selected, 'values')

### Class to create new contact window ###
class New_contact_window:
    def __init__(self, tab_name):
        self.window = tab_name
        self.table_name = tab_name

        self.window = Toplevel()
        self.window.title("Add New " + self.table_name)
        self.frame = Frame(self.window)
        self.frame.pack(fill="both", expand=1, pady=10)
        self.detail_name_dictionary = {}
        self.detail_name_list_keys = []
    def create_entry_boxes(self, column_names):      
        self.column_names = column_names

        for detail_name in self.column_names:
            self.label = Label(self.frame, text=detail_name) 
            self.label.grid(row=row, column=column, padx=10) 
            column +=1
            self.entry_box = Entry(self.frame) 
            self.entry_box.grid(row=row, column=column, padx=10)
            row +=1
            column -=1

            self.detail_name_dictionary[detail_name] = self.entry_box                

    def save_button(self):
        self.save_button = Button(self.frame, text="Save", command=self.on_save_button)
        self.save_button.grid(row=11, column=2, padx=10, pady=10) 
    def on_save_button(self):
        values = []
        if len(self.entry_box.get()) == 0:
            for detail_name in self.detail_name_list_keys:
                entry_value = self.detail_name_dictionary[detail_name].get() 
            values = ('(' + str(', '.join([str(i[0]) for i in values])) + ')')

            conn = sqlite3.connect('Bookkeeping_Database.sqlite3')
            cur = conn.cursor()
            cur.execute("CREATE TABLE IF NOT EXISTS " + self.table_name + " (" + " TEXT, ".join(self.detail_name_list_keys) +" TEXT)")
            cur.execute("INSERT INTO "+ self.table_name +"(" + ", ".join(self.detail_name_list_keys) + ") VALUES" + values + "", inputted_data,)

            saved_label = Label (self.frame, text="Saved") 
            saved_label.grid(row=12, column=2)


    def close_button(self):
        self.close_button = Button(self.frame, text="Close", command=self.window.destroy)
        self.close_button.grid(row=11, column=1, padx=10, pady=10)    

### Class to create contact edit window ###
class Edit_contact_window(New_contact_window):
    def __init__ (self, tab_name):
        self.window = tab_name
        self.table_name = tab_name

        self.window = Toplevel()
        self.window.title("Edit " + self.table_name)
        self.frame = Frame(self.window)
        self.frame.pack(fill="both", expand=1)
        self.detail_name_dictionary = {}
        self.detail_name_list_keys = []    

### Add contact tabs ###
column_names = [    "ID",

customer_tab = Create_contact_tab("Customers", "Add New Customer", column_names)

vendor_tab = Create_contact_tab("Vendors", "Add New Vendor", column_names)

I am going to run your code and see what is up.
Maybe add a function for refreshing the rows when you switch to other tab and back again.
The View class adds an expose event to Frame. The expose_event() method is called when the View becomes visible. In the example I use this to update a control in the View to some global value shared by all the views. Type a value in the entry box and <Enter>. If you change to a different tab the entry widget is updated to reflect the shared value.
import tkinter as tk
from tkinter import ttk

class View(tk.Frame):
    """A frame with an expose event"""
    shared_text = ''

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.bind('<Expose>', self.expose_event)

        self.local_text = tk.StringVar()
        self.entry = tk.Entry(self, textvariable=self.local_text)
        self.entry.bind('<Return>', self.set_value)
    def set_value(self, event):
        """Called when enter key is pressed in entry widget"""
        View.shared_text = self.local_text.get()

    def expose_event(self, event):
        """Called when I become visible"""

root = tk.Tk()
notebook = ttk.Notebook(root)
notebook.pack(fill=tk.BOTH, expand=tk.YES)
for i in range(5):
    notebook.add(View(notebook), text=str(i))
This solution only works for data that may have changed while the View was not visible and must be updated when it becomes visible. This will work great for something like a notebook if the notebook is self contained; i.e. only pages in the notebook can change values displayed in other pages and only one page can be visible at a time. It may not be applicable to your problem.
Thank you for your replies.

I ended up having to enter the 'insert' code from populate_tab_tree each time I needed it instead of reusing the method, and setting count to global so I'm not trying to overwrite previous inserts.

I also had to clear the table before inserting.