8. Buttons, the table and starting the program

Lines 129–146

The last part puts everything together: seven buttons in a frame, the products table, the resize behaviour, the first fill of the table and, finally, the main loop that keeps the window open.

Code for this part

shop_manager.py, lines 129–146
129buttons = [('افزودن کالا', add), ('ویرایش کالا', edit), ('حذف کالا', delete),130           ('ثبت فروش', sell), ('جست‌وجو', search), ('نمایش همه', refresh), ('گزارش فروش', report)]131frame = ttk.Frame(root)132frame.grid(row=4, column=0, columnspan=4, padx=10, pady=12)133for i, (label, action) in enumerate(buttons):134    ttk.Button(frame, text=label, command=lambda a=action: run(a)).grid(row=i // 4, column=i % 4, padx=4, pady=4)135 136columns = ('name', 'buy', 'sell', 'qty')137table = ttk.Treeview(root, columns=columns, show='headings', height=13)138for key, label in [('name', 'نام کالا'), ('buy', 'قیمت خرید'), ('sell', 'قیمت فروش'), ('qty', 'موجودی')]:139    table.heading(key, text=label)140    table.column(key, width=150, anchor='center')141table.grid(row=5, column=0, columnspan=4, padx=10, pady=10, sticky='nsew')142table.bind('<<TreeviewSelect>>', choose)143root.grid_rowconfigure(5, weight=1)144root.grid_columnconfigure(3, weight=1)145refresh()146root.mainloop()

Click a line number to jump to its explanation; click “line …” in an explanation to highlight that line in the code.

Line by line

line 129buttons = [('افزودن کالا', add), ('ویرایش کالا', edit), ('حذف کالا', delete),
A list of (button label, function) pairs. The functions are written without parentheses, so the function objects themselves go into the list instead of being called.
line 130('ثبت فروش', sell), ('جست‌وجو', search), ('نمایش همه', refresh), ('گزارش فروش', report)]
The rest of the same list; the open bracket on the previous line lets the list span two lines. The “show all” button is wired straight to refresh, which shows every product when called with no arguments.
line 131frame = ttk.Frame(root)
Creates a Frame inside the window so the buttons get a grid of their own.
line 132frame.grid(row=4, column=0, columnspan=4, padx=10, pady=12)
Places the frame on row 4 of the window, below the four form rows. columnspan=4 makes it span four columns.
line 133for i, (label, action) in enumerate(buttons):
Loops over the buttons; i is the button's index (0 to 6).
line 134ttk.Button(frame, text=label, command=lambda a=action: run(a)).grid(row=i // 4, column=i % 4, padx=4, pady=4)
Creates a button and places it in the frame. command is the function called on a click. lambda a=action: run(a) builds a small anonymous function that calls run with this button's function. a=action captures the current value right away; without it every button would run the loop's last value (report). i // 4 gives the row and i % 4 the column, so four buttons sit on the first row and three on the second.
line 135
A blank line.
line 136columns = ('name', 'buy', 'sell', 'qty')
The IDs of the table's four columns, as a tuple.
line 137table = ttk.Treeview(root, columns=columns, show='headings', height=13)
Creates the table (Treeview). show='headings' hides the default tree column (#0) so only our columns remain, and height=13 shows thirteen rows.
line 138for key, label in [('name', 'نام کالا'), ('buy', 'قیمت خرید'), ('sell', 'قیمت فروش'), ('qty', 'موجودی')]:
Loops over the column IDs and their header labels. The last column's header means “stock” rather than “quantity”.
line 139table.heading(key, text=label)
Sets the header text of the column.
line 140table.column(key, width=150, anchor='center')
Makes the column 150 pixels wide with centred text.
line 141table.grid(row=5, column=0, columnspan=4, padx=10, pady=10, sticky='nsew')
Places the table on row 5, across four columns. sticky='nsew' sticks it to all four sides so it stretches with its cell.
line 142table.bind('<<TreeviewSelect>>', choose)
Binds the virtual event <<TreeviewSelect>> to choose: every time the table's selection changes, choose runs.
line 143root.grid_rowconfigure(5, weight=1)
Gives row 5 (the table) a weight of 1, so extra height goes to it when the window grows.
line 144root.grid_columnconfigure(3, weight=1)
Gives column 3 a weight of 1, so extra width goes there and the table, which spans up to column 3, gets wider.
line 145refresh()
Fills the table for the first time with the products loaded from disk.
line 146root.mainloop()
Starts tkinter's main loop. The program waits here for clicks and key presses and does not get past this line until the window is closed.

Note

The order in which the whole file runs: class definition → create shop and the window → form → define the functions → buttons → table → refresh() → mainloop(). The functions on lines 77–127 do not run when they are defined; they run only when a button is clicked, or on line 145.

How it connects to the rest of the code

See also

buttons
Its functions are defined in part 6: add line 93, edit line 96, delete line 99, sell line 102, search line 105, report line 109, plus refresh on line 113.
run
Defined on line 84.
table
Used in refresh (line 114, line 115, line 118) and choose (line 121, line 124).
choose
Defined on line 120.
grid
The form takes rows 0 to 3 (line 72 and line 74), the buttons row 4 and the table row 5.

Check your understanding

Try to answer each question before opening it.

  1. What goes wrong if line 134 uses lambda: run(action) without a=action?

    Show answer

    The lambda reads action when it is clicked, not when it is created, so every button runs the loop's last value, report.

  2. Where does the button with index 5 appear?

    Show answer

    Row 5 // 4 = 1, column 5 % 4 = 1: second row, second column. It is the “show all” button.

  3. Why must root.mainloop() be the last line?

    Show answer

    It blocks until the window is closed; code after it would only run after the program has finished.

  4. What does show='headings' hide on line 137?

    Show answer

    The default tree column #0, so only the four data columns are shown.