Al Lelopath
Al Lelopath

Reputation: 6778

Display large table with grid

I am trying to display with a grid a table that is 270 rows and 70 columns It is apparently too big to display all in one shot. If I limit the rows to 50 it takes 12 seconds, then more as I increase of course, and then at some point it goes wonky. Is there to first set the label data for say 20 rows, then display, then set for the next 20, add those to the display, and so on?

def populate_using_tkinter(frame, project_list):

    current_row_number = 0;

    # Columns ********************************************************************************************************
    label_id_column = Tkinter.Label(frame, text=Constants.PROJECT_COLUMN_TITLE_Id, borderwidth=GRID_BORDER_WIDTH, relief="solid", background=row_header_color)
    <more columns>
    label_ContractorID_column = Tkinter.Label(frame,text = Constants.PROJECT_COLUMN_TITLE_ContractorID, borderwidth = GRID_BORDER_WIDTH,relief = "solid")

    label_id_column.grid(row=current_row_number, column=Constants.PROJECT_ID_COLUMN, sticky="nsew")
    <more columns>
    label_ContractorID_column.grid(row=current_row_number, column=Constants.PROJECT_ContractorID_COLUMN, sticky="nsew")

    current_row_number +=1    
    frame.rowconfigure(current_row_number, minsize=row_height, weight=0)

    for project in project_list:
        project_id = project[0]
        <more assignments>
        project_ContractorID = project[70]

        # Data ********************************************************************************************************
        try:
            label_project_id = Tkinter.Label(frame, text=project_id, borderwidth=GRID_BORDER_WIDTH, relief="solid", background=row_color)
            <more data>
            label_project_ContractorID=Tkinter.Label(frame,text=projectContractorID,anchor="w",borderwidth=GRID_BORDER_WIDTH,relief="solid", background=row_color)

            label_project_id.grid(row=current_row_number, column=Constants.PROJECT_ID_COLUMN, sticky="nsew")
            <more data>
            label_project_ContractorID.grid(row=current_row_number, column=Constants.PROJECT_ContractorID_COLUMN, sticky="nsew") 

        except IndexError:
            print ("[ERROR] IndexError: " + str(current_row_number) )

        current_row_number +=1    


def main():

    project_list = <get from database>    # 270 x 70

    root = Tkinter.Tk()

    canvas = Tkinter.Canvas(root, borderwidth=0, background="#ffffff")
    frame = Tkinter.Frame(canvas, background="#ffffff")

    canvas.pack(side="left", fill="both", expand=True)
    canvas.create_window((4,4), window=frame, anchor="nw")

    frame.bind("<Configure>", lambda event, canvas=canvas: onFrameConfigure(canvas))

    populate_using_tkinter(frame, project_list) 

    root.geometry("1000x600")

    root.mainloop()

Upvotes: 0

Views: 317

Answers (1)

Henry Yik
Henry Yik

Reputation: 22503

This sounds like a job more suited for treeview widget. But if you want to use a table of labels instead, one way is to use a generator combined with after method:

import tkinter as tk

root = tk.Tk()
data = {i:i for i in range(200)}

def display_data():
    row = 0
    for k,v in data.items():
        tk.Label(root,text=k).grid(row=row,column=0)
        tk.Label(root,text=v).grid(row=row,column=1)
        row+=1
        if not row % 5: #configure this to display the number of rows each second
            root.after(1000, fetch)
            yield

a = display_data()

def fetch():
    try:
        next(a)
    except StopIteration:
        return

root.after(1000, fetch)

root.mainloop()

Or you can put it in a treeview instead. Usually I find this easier to display data and it also comes in with many handy methods which allows you to sort, export etc. I also added both a vertical and horizontal scrollbar for reference.

from tkinter import ttk
import tkinter as tk

root = tk.Tk()

class TreeFrame(tk.Frame):
    def __init__(self,master,**kwargs):
        tk.Frame.__init__(self,master,**kwargs)
        self.tree = ttk.Treeview(self, selectmode='extended', height=24)
        self.tree.grid(row=0,column=0,sticky="nsew")
        vsb = ttk.Scrollbar(self, orient="vertical",command=self.tree.yview)
        vsb.grid(row=0,column=1,sticky="ns")
        hsb = ttk.Scrollbar(self, orient="horizontal",command=self.tree.xview)
        hsb.grid(row=1,column=0,sticky="ew")
        self.tree.configure(yscrollcommand=vsb.set)
        self.tree.configure(xscrollcommand=hsb.set)
        header = [i for i in range(70)]
        self.tree["columns"] = header
        self.tree['show'] = 'headings'
        self.start = 0
        for i in range(len(header)):
            self.tree.column(header[i], width=15, minwidth=27, anchor="w")
            self.tree.heading(header[i], text=header[i], anchor='w')

    def dummy_data(self):
        for i in range(self.start, self.start+20):
            current = self.tree.insert("","end",values=[i for _ in range(70)])
            self.tree.see(current)
        self.start += 20
        if self.start >= 270:
            return
        else:
            root.after(1000,self.dummy_data)

tree_frame = TreeFrame(root)
tree_frame.pack()

tk.Button(root,text="Add dummy data",command=tree_frame.dummy_data).pack()

root.mainloop()

Upvotes: 1

Related Questions