6. Reading the form, run() and the button handlers¶
Lines 77–111
This part is the bridge between the window and the Shop class. values converts the form text into numbers, run executes any action safely and reports errors, and six short functions each do the work of one button.
Code for this part¶
77def values():78 name = fields['name'].get().strip()79 buy = float(fields['buy'].get())80 sell = float(fields['sell'].get())81 qty = int(fields['qty'].get())82 return name, buy, sell, qty83 84def run(action):85 try:86 action()87 if action is not search: refresh()88 except (ValueError, TypeError) as exc:89 messagebox.showerror('خطا', str(exc))90 except OSError as exc:91 messagebox.showerror('خطای فایل', str(exc))92 93def add():94 shop.add(*values())95 96def edit():97 shop.edit(*values())98 99def delete():100 shop.delete(fields['name'].get().strip())101 102def sell():103 shop.sell(fields['name'].get().strip(), int(fields['qty'].get()))104 105def search():106 name = fields['name'].get().strip().lower()107 refresh(name)108 109def report():110 count, income = shop.report()111 messagebox.showinfo('گزارش فروش', f'تعداد فروختهشده: {count}\nدرآمد کل فروش: {income:,.0f}')
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 78
name = fields['name'].get().strip()¶ get()returns the text in the name box andstrip()removes leading and trailing spaces, so"pen "and"pen"count as the same name.- line 79
buy = float(fields['buy'].get())¶ - Converts the purchase price to a
float. If the text is not a number (or is empty), aValueErroris raised and caught inrun(line 88). - line 82
return name, buy, sell, qty¶ - Returns the four values as a tuple, in exactly the order of the parameters of
Shop.add(line 28) andShop.edit(line 36). - line 84
def run(action):¶ - The central
runfunction. Its argumentactionis itself a function — in Python a function can be passed around like any other value. Every button goes throughrun(line 134). - line 87
if action is not search: refresh()¶ - If the action finished without an error, refreshes the table with the current data (line 113); if an error occurred, this line never runs.
is notchecks thatactionis not thesearchfunction (line 105):searchhas already filled the table with the filtered rows, and an unfilteredrefresh()here would wipe out the search result. Anifmay share its line with a single statement. - line 88
except (ValueError, TypeError) as exc:¶ - Catches input and logic errors: every
raise ValueErrorin the class and the conversion errors on line 79–line 81.as excbinds the exception object toexc. - line 89
messagebox.showerror('خطا', str(exc))¶ - Shows an error dialog.
str(exc)is the message that was given toraise. - line 90
except OSError as exc:¶ - Catches file errors, for example when
save(line 15) is not allowed to write. - line 93
def add():¶ - Handler for the “add product” button. It shares its name with
Shop.add, but they don't clash: one is a global function, the other an attribute of theshopobject. - line 94
shop.add(*values())¶ values()returns a four-item tuple and the star*unpacks it into four separate arguments forshop.add— the same asshop.add(name, buy, sell, qty).- line 100
shop.delete(fields['name'].get().strip())¶ - Deleting only needs the name, so the name box is read directly instead of calling
values(). That is why empty price fields don't cause an error here. - line 103
shop.sell(fields['name'].get().strip(), int(fields['qty'].get()))¶ - Reads the name and the quantity and passes them to
shop.sell. Note that the quantity box is used both for stock and for the number of items sold. - line 106
name = fields['name'].get().strip().lower()¶ - Reads the name box and lower-cases it with
lower(), so searches for Latin-script names ignore case. - line 107
refresh(name)¶ - Fills the table with only the products whose name contains this text (line 113).
Note
In an earlier version line 87 was a plain refresh(), and the search button did nothing visible: search() filtered the table (line 107), then the unfiltered refresh() immediately brought every product back. The if action is not search condition fixes this. It is written on the same line so that the line numbers below it stay the same.
How it connects to the rest of the code¶
See also
values()- Used in
addline 94 andeditline 97. run(action)- Used on line 134 for all seven buttons. It calls
refreshitself on line 87, except for the search button. add,edit,delete,sell,search,report- Paired with the button labels in the
buttonslist (line 129 and line 130). - Class methods
add→Shop.addline 28,edit→Shop.editline 36,delete→Shop.deleteline 44,sell→Shop.sellline 50,report→Shop.reportline 62.messagebox- Imported on line 4.
Check your understanding¶
Try to answer each question before opening it.
What does the
*do inshop.add(*values())?Show answer
It unpacks the four-item tuple into four separate arguments:
shop.add(name, buy, sell, qty).The user types
abcas the price and clicks “add”. Follow what happens.Why doesn't
deletecallvalues()?Show answer
Deleting only needs the name;
values()would fail on empty price fields.What would the search button do without the condition on line 87?
Show answer
Nothing visible:
searchfilters the table, thenrefresh()immediately shows every product again.What does
{income:,.0f}print for1234567.8?Show answer
1,234,568— thousands separators, rounded to no decimals.