-2

I have the following code which is working, but I don't understand how to add a scroll bar to the table, and how to shows header at the top of each column.

Also I would like to display gridlines, but I struggle to do it.

Any help would be appreciated !

import tkinter as tk

class Example(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
        b = tk.Button(self, text="Done!", command=self.upload_cor)
        b.pack()
        table = tk.Frame(self)
        table.pack(side="top", fill="both", expand=True)

        data = (
            (45417, "rodringof", "CSP L2 Review", 0.000394, "2014-12-19 10:08:12", "2014-12-19 10:08:12"),
            (45418, "rodringof", "CSP L2 Review", 0.000394, "2014-12-19 10:08:12", "2014-12-19 10:08:12"),
            (45419, "rodringof", "CSP L2 Review", 0.000394, "2014-12-19 10:08:12", "2014-12-19 10:08:12"),
            (45420, "rodringof", "CSP L2 Review", 0.000394, "2014-12-19 10:08:12", "2014-12-19 10:08:12"),
            (45421, "rodringof", "CSP L2 Review", 0.000394, "2014-12-19 10:08:12", "2014-12-19 10:08:12"),
            (45422, "rodringof", "CSP L2 Review", 0.000394, "2014-12-19 10:08:12", "2014-12-19 10:08:12"),
            (45423, "rodringof", "CSP L2 Review", 0.000394, "2014-12-19 10:08:12", "2014-12-19 10:08:12"),
        )

        self.widgets = {}
        row = 0
        for rowid, reviewer, task, num_seconds, start_time, end_time in (data):
            row += 1
            self.widgets[rowid] = {
                "rowid": tk.Label(table, text=rowid),
                "reviewer": tk.Label(table, text=reviewer),
                "task": tk.Label(table, text=task),
                "num_seconds_correction": tk.Entry(table),
                "num_seconds": tk.Label(table, text=num_seconds),
                "start_time": tk.Label(table, text=start_time),
                "end_time": tk.Label(table, text=start_time)
            }

            self.widgets[rowid]["rowid"].grid(row=row, column=0, sticky="nsew")
            self.widgets[rowid]["reviewer"].grid(row=row, column=1, sticky="nsew")
            self.widgets[rowid]["task"].grid(row=row, column=2, sticky="nsew")
            self.widgets[rowid]["num_seconds_correction"].grid(row=row, column=3, sticky="nsew")
            self.widgets[rowid]["num_seconds"].grid(row=row, column=4, sticky="nsew")
            self.widgets[rowid]["start_time"].grid(row=row, column=5, sticky="nsew")
            self.widgets[rowid]["end_time"].grid(row=row, column=6, sticky="nsew")

        table.grid_columnconfigure(1, weight=1)
        table.grid_columnconfigure(2, weight=1)
        # invisible row after last row gets all extra space
        table.grid_rowconfigure(row+1, weight=1)

    def upload_cor(self):
        for rowid in sorted(self.widgets.keys()):
            entry_widget = self.widgets[rowid]["num_seconds_correction"]
            new_value = entry_widget.get()
            print("%s: %s" % (rowid, new_value))

if __name__ == "__main__":
    root = tk.Tk()
    Example(root).pack(fill="both", expand=True)
    root.mainloop()
TourEiffel
  • 4,034
  • 2
  • 16
  • 45

1 Answers1

1

The proper way to display a table in tkinter will be to use the ttk.Treeview widget. It is quite easy to use, check this:

import tkinter as tk
from tkinter import ttk


class ScrollTree(ttk.Treeview):
    def __init__(self, master, *args, **kwargs):
        ttk.Treeview.__init__(self, master, *args, **kwargs)

        sb = tk.Scrollbar(master, orient='vertical', command=self.yview) # Create a scrollbar
        sb.grid(row=0, column=1, sticky='ns')
        self.config(yscrollcommand=sb.set)


if __name__ == "__main__":

    root = tk.Tk()

    data = (...)

    tree_frame = tk.Frame(root)
    tree_frame.pack()

    columns = [f'Column {i+1}' for i in range(len(data[0]))] # List of column names for all the columns of the data
    tree = ScrollTree(tree_frame, columns=columns, show='headings')
    tree.grid(row=0, column=0)

    for col in columns:
        tree.heading(col, text=col, anchor='center') # Add a heading in the given `col` as ID
        tree.column(col, anchor='center') # Properties for the column with `col` as ID

    for i in data:
        tree.insert('', 'end', values=i) # Insert each tuple into the treeview

    root.mainloop()

You are just creating a custom class for a treeview with a vertical scrollbar, you can also just do this entirely procedural, but since you had the code already, I just modified it. There is much more that the ttk.Treeview can do.


If you still want to use the other approach and make a grid of labels to display data, then you can do that by increasing the row value of the widgets by 1 (apparently a bug in your code allows for this to happen automatically, so you shouldn't have to make any changes) and then making new labels for headers outside the loop:

row = 0
for rowid, reviewer, task, num_seconds, start_time, end_time in (data):
    row += 1

    self.widgets[rowid]["rowid"].grid(row=row, column=0, sticky="nsew")
    self.widgets[rowid]["reviewer"].grid(row=row, column=1, sticky="nsew")
    self.widgets[rowid]["task"].grid(row=row, column=2, sticky="nsew")
    ...

tk.Label(table, text='Header 1').grid(row=0, column=0)
tk.Label(table, text='Header 2').grid(row=0, column=1)
tk.Label(table, text='Header 3').grid(row=0, column=2)
...

Now to add a scrollbar, you can follow this question Tkinter scrollbar for frame

Delrius Euphoria
  • 14,910
  • 3
  • 15
  • 46