1
\$\begingroup\$

I am using a code similar to the following example to create a table with tkinter using Python 3:

  • Each cell is individually created as a ttk.Label and displayed using .grid(row, column)

  • Some of my values get updated while the program is running with tk.StringVar().set()

  • Each value is unique and has it's own variable name count1 count2

This example seems short, but in my program I have a few more rows being displayed and each row has 2 StringVar() that I need to keep updated. Overall, it's a very large for loop because it has to check if it's in the correct row & column combination (row 1 column 0 or row 2 column 0) before creating a StringVar().

  • Any suggestions on how to reduce the size of my for loop?
  • Are there better ways of creating tables that need a few values consistently updated?

Thank you for your time and Happy Holidays!

import time
import tkinter as tk
import tkinter.ttk as ttk
from threading import Thread

gui = tk.Tk()
gui.geometry('360x270')
gui.configure(bg='white')

style = ttk.Style()
style.theme_create('custom', settings={
    'header.TLabel': {'configure': {
        'background': 'white',
        'foreground': 'dark green',
        'font': 'Times 16 bold',
        'padding': (10, 0)}},
    'TLabel': {'configure': {'background': 'white', 'font': 'Times 12'}},
    'TFrame': {'configure': {'background': 'white'}}})
style.theme_use('custom')

table_frame = ttk.Frame(gui)
table_frame.pack(pady=(36, 0))

values = [('Count', 'Date', 'Time', 'Phrase'),
          ('5', '12/12/10', '03:15', 'blue car'),
          ('13', '09/09/98', '16:20', 'red door')]

total_rows = len(values)
total_columns = len(values[0])

for i in range(total_rows):
    for j in range(total_columns):
        if i == 0:
            label = ttk.Label(table_frame, text=values[i][j], style='header.TLabel')
            label.grid(row=i, column=j)
        elif i == 1:
            if j == 0:
                count1 = tk.StringVar()
                count1.set(values[i][j])
                label = ttk.Label(table_frame, textvariable=count1)
                label.grid(row=i, column=j)
            else:
                label = ttk.Label(table_frame, text=values[i][j])
                label.grid(row=i, column=j)
        elif i == 2:
            if j == 0:
                count2 = tk.StringVar()
                count2.set(values[i][j])
                label = ttk.Label(table_frame, textvariable=count2)
                label.grid(row=i, column=j)
            else:
                label = ttk.Label(table_frame, text=values[i][j])
                label.grid(row=i, column=j)


def increment_count():
    increment_count.status = 'run'

    while increment_count.status == 'run':
        new_minute1 = int(count1.get()) + 1
        count1.set(str(new_minute1))

        new_minute2 = int(count2.get()) - 1
        count2.set(str(new_minute2))

        time.sleep(1)


Thread(target=increment_count).start()

gui.mainloop()
increment_count.status = 'exit'
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

As I suspected, there's already a thing for this - a TreeView. Strongly prefer built-in widgets that get the job done, leaving the construction of individual elements as a last resort if the built-in widget doesn't at all meet your needs.

There's plenty of examples on how to use this as a table, but if I were you I'd start with the reference documentation.

Remove the first row of your values and use it as a dedicated heading, instead. Break your i/j loop into two halves - a heading half, and a body half.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Thanks a lot! I didn't even know you could use TreeView like that, I thought it was just for dropdown menus. \$\endgroup\$ Jan 4, 2021 at 17:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.