How can I have imported modules access tkinter widgets and variables? - python

I had this Cafe Management System whom I've separated the gui and functions into modules.
Here are some snippets:
main.py
from tkinter import *
import checkbox_operation
import receipt_operation
class cafemanagementsystem:
def __init__(self, cms):
self.cms = cms
cms.title("Cafe Management System")
self.b1var = IntVar(value=1)
self.b1v = StringVar()
self.b1v.set("0")
self.b1 = Checkbutton(self.bevmenu, command=self.check, text="Latte", variable=self.b1var, onvalue=1, offvalue=0).grid()
self.b1a = Entry(self.bevmenu, bd=2, textvariable=self.b1v)
self.b1a.grid()
self.rcpt = Text(self.rcptmain, width=50, height=30, bd=4)
self.rcpt.grid()
self.btnrcpt = Button(self.rcptbtn, command=receipt_operation.receipt, text="Receipt").grid()
self.btnrst = Button(self.rcptbtn, command=receipt_operation.reset, text="Reset").grid()
def check(self):
checkbox_operation.check(self)
def receipt(self):
receipt_operation.receipt(self)
checkbox_operation.py
def check(cafemanagementsytem_inst):
if b1var.get() == 1:
b1a.config(state=NORMAL)
elif b1var.get() == 0:
b1a.config(state=DISABLED)
b1v.set("0")
receipt_operation.py
def receipt():
rcpt.insert(END, "Offical Receipt\n")
rcpt.insert(END, "Latte \t\t\t\t" + b1v.get() + "\n")
My problem is that I can't get check() and receipt() to work. Also, def check(self) and def receipt(self) gives the following error:
TypeError: check()/receipt() takes 0 positional arguments but 1 was given
Are there any solutions for this? Also, please tell me if the way I wrote the code contributed to the problem as I've been stuck in this problem for almost a week.

You need to pass the proper variables into those other functions. I'm wondering why you have checkbox_operation in a separate file, when it should be part of the class. It's not good practice that those external functions need to have such detailed knowledge of the internal workings of the class.
...
def check(self):
checkbox_operation.check(self)
def receipt(self):
receipt_operation.receipt(self)
def check(cafe):
if cafe.b1var.get() == 1:
cafe.b1a.config(state=NORMAL)
elif cafe.b1var.get() == 0:
cafe.b1a.config(state=DISABLED)
cafe.b1v.set("0")
def receipt(cafe):
cafe.rcpt.insert(END, "Offical Receipt\n")
cafe.rcpt.insert(END, "Latte \t\t\t\t" + cafe.b1v.get() + "\n")

Related

Choosing from a List of methods in a tkinter Button

Good Day,
I'm new to this forum (and quite new to programming), so I hope my question is properly formulated.
I've been trying to create a GUI in python using tkinter, and I want to have two buttons calling methods of two different classes. One method is defining an integer, the second one is reporting content. I'd have a list of objects of the latter class, and I want to choose the right instance by the integer. Here's a MWE:
import tkinter as tk
class data:
def __init__(self, content):
self.content = content
def report(self):
print("This is reported as self.content:" + str(self.content)) #This doesnt report the correct value for some reason?
print("The Class does register the correct idx:" + str(Selector.idx))
print("Using the Dict the correct value can be returned:" + str(vocables[Selector.idx].content))
class increment:
def __init__(self):
self.idx = 0
def increase(self):
self.idx += 1
print(self.idx)
vocables[self.idx].report()
root = tk.Tk()
Selector = increment()
vocables = []
for id in range(10):
vocables.append(data(id))
# print(vocables[id].content)
CheckVocable = tk.Button(root, text="Report", command=vocables[Selector.idx].report)
CheckVocable.pack()
NextVocable = tk.Button(root, text="Increase Index", command=Selector.increase)
NextVocable.pack()
root.mainloop()
I do not understand why the print of line 8 always reports the value of the first item in the list (vocabules[0] in this instance) instead of my desired value, which is returned in all other print cases. Am I messing up the work with classes or is the button behavior confusing me?
Thanks in advance!

How can I test a function that is embedded in a method

I recently started doing python. The course I was on ended with an introduction to testing with doctest. I have written a program that uses Tkinter to display widgets and it works :-) . I am using version 3.7. However, testing it is another matter. I can test simple functions and methods, but I hit difficulties when I have a function inside a method. I am pasting below a stripped-down version of what I am trying to achieve. I tried first with doctest and it threw up an error:
"AttributeError: 'function' object has no attribute 'c_square'".
# counter.py
from tkinter import *
import doctest
count = 0
delay = 1000
class MyClass:
def __init__(self, master):
master.geometry("1000x500")
master.resizable(0, 0)
master.title("Display a counter")
frame1 = Frame(master)
frame1.pack()
label1 = Label(frame1, font = ('Courier', 15 , 'bold'))
label1.grid(row = 0, column = 0)
self.my_counter(label1)
label2 = Label(frame1, font = ('Courier', 15 , 'bold'))
label2.grid(row = 0, column = 1)
self.square_of_count(label2)
# This method recursively increments a counter and displays the count.
def my_counter(self, lbl):
def increment_count():
global count
global delay
count += 1
string = str(count)
lbl.config(text = string)
lbl.after(delay, increment_count)
increment_count()
# This method takes the square of the counter and displays the result.
def square_of_count(self, lbl):
def c_square():
global count
squ = count * count
string = str(squ)
lbl.config(text=string)
lbl.after(delay, c_square)
return squ
c_square()
def test_c_square(number):
"""
>>> test_c_square(2)
4
"""
global count
count = number
master = Tk()
frame1 = Frame(master)
label = Label(frame1, font = ('Courier', 15 , 'bold'))
return MyClass.square_of_count.c_square(MyClass.square_of_count.c_square)
def main():
""" # main body commented out for test purposes.
root = Tk()
a = MyClass(root)
root.mainloop()
"""
doctest.testmod(verbose=True)
if __name__ == "__main__":
main()
I am using a separate test function, so that I can initialise my counter.
Then someone suggested that I try unittest, so I wrote this :
import unittest
import counter
class TestCounter(unittest.TestCase):
counter.count = 2
print("count = ", counter.count)
def square_of_count(self):
result = counter.c_square()
self.assertEqual(result, 4)
result = counter.c_square()
self.assertNotEqual(result, 3)
if __name__ == '__main__':
unittest.main()
This runs without throwing up any errors, the purpose of it is to set a value to the variable 'count' and read back the result. But I get the same response whatever value I test for, so I do not believe it is working right. I also tried variations on a theme, but I just got error messages.
Can someone please point out what I am doing wrong, I have looked about various forums and tutorials but have not seen this question asked before.
I would appreciate an answer that is easy to follow, I am asperger / dyslexic and find it difficult to learn new material. A correction with explanation would be most helpful. Thank you.
First of all, avoid this kind of nesting the functions. In your particular case I would highly suggest refactoring of a code in manner of creating some help private methods which you will call from the main ones, or even create whole new utility class:
class Util:
def _init_(self):
self.name = "Utility"
def add_two_numbers(self, first, second):
if(isinstance(first, int) and isinstance(second, int)):
return first+second
class SomeFancyClass:
def __init__(self):
self.util = Util()
self.constant = 4
# This method recursively increments a counter and displays the count.
def my_fancy_math(self, first, second):
return self.constant * self.util.add_two_numbers(first, second)
FancyVar = SomeFancyClass()
print(FancyVar.my_fancy_math(5, 6))
In case you dont want to change your code (for some reason), there is extremely dirty way to access your inner function. Again, a bit stupidly modified example made from your code:
#!/usr/bin/python
# -*- coding: utf-8 -*-
# counter.py
from tkinter import *
import doctest
import types
count = 0
delay = 1000
class MyClass:
def __init__(self, smth1):
self.something = smth1
# This method recursively increments a counter and displays the count.
def my_counter(self, lbl):
def increment_count():
global count
global delay
count += 1
string = str(count)
lbl.config(text=string)
lbl.after(delay, increment_count)
increment_count()
# This method takes the square of the counter and displays the result.
def square_of_count(self, lbl):
def test_function1(self, first, second):
return first+second
def c_square():
global count
squ = count * count
string = str(squ)
lbl.config(text=string)
lbl.after(delay, c_square)
return squ
c_square()
def test_function(self, st1):
print(st1)
def test_c_square(number):
global count
count = number
master = Tk()
frame1 = Frame(master)
label = Label(frame1, font=('Courier', 15, 'bold'))
return MyClass.square_of_count.c_square(MyClass.square_of_count.c_square)
def main():
doctest.testmod(verbose=True)
if __name__ == '__main__':
# main()
print('done')
test_function = types.FunctionType(MyClass.square_of_count.__code__.co_consts[1],
{}, None, (), ())
obj = MyClass("Hi")
sum1 = test_function("", 1, 2)
print(sum1)

How to add method overriding & overloading to Bank Account in Python Tkinter

I am very new to python let alone Tkinter, and am creating an object oriented bank account, i have a working program, however when designing the application i planned to add all the features of OOP into the code, how would i add method overriding and overloading to this program whilst keeping its full functionality? Give your insight.
Bank Account Code
from tkinter import *
from random import randint
import time
class Account:
def __init__(self, init_balance=0):
self.balance = init_balance
def deposit(self, amount):
self.balance += amount
def withdraw(self, amount):
self.balance -= amount
def get_balance(self, init_balance, rate):
return self.get_balance() * self._rate
class InterestAccount(Account):
def __init__(self, init_balance=0, rate=0.1):
super().__init__(init_balance)
self._rate = rate
def interest(self):
return self.balance * self._rate
class GUI(Tk):
def __init__(self):
Tk.__init__(self)
self.title('Bank Account')
#Menu#
menu = Menu(self)
acct_type_menu = Menu(menu)
menu.add_cascade(label='Account Type', menu=acct_type_menu)
acct_type_menu.add_command(label='Standard', command=self.set_type_standard)
acct_type_menu.add_command(label='Interest', command=self.set_type_interest)
self.config(menu=menu)
#Account#
start_balance = randint(100, 500)
self.acct = Account(start_balance)
self.my_interest = InterestAccount(start_balance)
self.interest = self.my_interest.balance + self.my_interest.interest()
#Labels#
Label(self, text='Current Balance:').pack()
self.balance_label = Label(self, text='Error: Select account type')
self.balance_label.pack()
#Button#
btns_frame = Frame(self)
btns_frame.pack(side=TOP, fill=X)
Button(btns_frame, text='Deposit', width=13, command=self.deposit).pack(side=LEFT)
Button(btns_frame, text='Withdraw', width=13, command=self.withdraw).pack(side=RIGHT)
#Textbox#
vcmd = (self.register(self.onValidate), '%S')
self.text = Entry(self, validate='key', vcmd=vcmd)
self.text.pack()
def onValidate(self, S):
if S in '0123456789.':
return True
return False
def set_type_standard(self):
self.acct_type = 'standard'
self.balance_label.config(text=round(self.acct.balance, 2))
def set_type_interest(self):
self.acct_type = 'interest'
self.balance_label.config(text=round(self.interest, 2))
def clear_entry(self):
self.text.delete(0, END)
def deposit(self):
if self.acct_type == 'interest':
a = int(self.text.get())
self.interest += a
self.balance_label.config(text=round(self.interest, 2))
elif self.acct_type == 'standard':
a = int(self.text.get())
self.acct.balance += a
self.balance_label.config(text=round(self.acct.balance, 2))
else:
self.balance_label.config(text='Error: Select account type')
self.clear_entry()
def withdraw(self):
if self.acct_type == 'interest':
a = int(self.text.get())
self.interest -= a
self.balance_label.config(text=round(self.interest, 2))
elif self.acct_type == 'standard':
a = int(self.text.get())
self.acct.balance -= a
self.balance_label.config(text=round(self.acct.balance, 2))
else:
self.balance_label.config(text='Error: Select account type')
self.clear_entry()
if __name__ == '__main__':
GUI().mainloop()
Function overloading (also method overloading) is a programming concept that allows programmers to define two or more functions with the same name and in the same scope.
You already have some "overloading" in your code:
class InterestAccount(Account):
def __init__(self, init_balance=0, rate=0.1):
When creating a new InterestAccount object, it can be called with 0, 1, or 2 parameters because of those default values specified. As mentioned in this SO answer, Python is dynamically-typed, so you don't need to create multiple of the same method with different parameters like you do in Java.
Overriding is an object-oriented programming feature that enables a child class to provide different implementation for a method that is already defined and/or implemented in its parent class...
You have a great opportunity to override the deposit and withdraw methods in your InterestAccount class because it inherits from Account and currently uses its parent's implementations of these methods. Simply define deposit and withdraw methods in your InterestAccount class, but do something different than what is done in the parent class.

Can you make a def method that makes more def methods for Python

I've been playing around with tkinter a little and I found that you have to make a def method to use buttons. So I wanted to make 13 buttons because I wanna make a calculator but I really didn't want to make 13 def methods that do very similar things. I tried doing a nested def method (I've never really done that before) but, from what I've tried, it won't work. Am I just doing it wrong or is it just impossible. If it is impossible, is there any other way to mass produce def methods besides a lot of copy and a lot of paste? Here's the code:
from tkinter import *
window=Tk()
window.geometry("500x500")
print("Restarting")
user=""
def oneb():
global user
print("1",end="")
user+="1"
def twob():
global user
user+="2"
print("2",end="")
def threeb():
global user
user+="3"
print("3",end="")
def fourb():
global user
user+="4"
print("4",end="")
def fiveb():
global user
user+="5"
print("5",end="")
def sixb():
global user
user+="6"
print("6",end="")
def sevenb():
global user
user+="7"
print("7",end="")
def eightb():
global user
user+="8"
print("8",end="")
def nineb():
global user
user+="9"
print("9",end="")
def zerob():
global user
user+="0"
print("0",end="")
def plusb():
global user
user+="+"
print("+",end="")
def minusb():
global user
print("-",end = "")
def equalb():
global user
if "+" in user:
user=user.partition("+")
symbol="+"
elif "-" in user:
user=user.partition("-")
symbol="-"
else:
print("=",user)
num1=user[0]
num2=user[2]
num1=int(num1)
num2=int(num2)
if symbol=="+":
answer=num1+num2
else:
answer=num1-num2
answer=str(answer)
print("="+answer)
heightb=5
widthb=10
#I know here I probably should've just made a def method.
one=Button(window, text="1",command=oneb,height=heightb,width=widthb)
one.grid(row=1,column=1)
two=Button(window, text="2",command=twob,height=heightb,width=widthb)
two.grid(row=1,column=2)
three=Button(window, text="3",command=threeb,height=heightb,width=widthb)
three.grid(row=1,column=3)
four=Button(window, text="4",command=fourb,height=heightb,width=widthb)
four.grid(row=2,column=1)
five=Button(window, text="5",command=fiveb,height=heightb,width=widthb)
five.grid(row=2,column=2)
six=Button(window, text="6",command=sixb,height=heightb,width=widthb)
six.grid(row=2,column=3)
seven=Button(window, text="7",command=sevenb,height=heightb,width=widthb)
seven.grid(row=3,column=1)
eight=Button(window, text="8",command=eightb,height=heightb,width=widthb)
eight.grid(row=3,column=2)
nine=Button(window, text="9",command=nineb,height=heightb,width=widthb)
nine.grid(row=3,column=3)
zero=Button(window, text="0",command=zerob,height=heightb,width=widthb)
zero.grid(row=4,column=2)
plus=Button(window, text="+", command=plusb,height=heightb, width=widthb)
plus.grid(row=2,column=4)
minus=Button(window,text="-", command=minusb,height=heightb, width=widthb)
minus.grid(row=1,column=4)
equal=Button(window,text="=", command=equalb,height=heightb, width=widthb)
equal.grid(row=3,column=4)
mainloop()
#button location var.grid(row=x,column=x)
You can make a function that returns a function.
For example,
def build_button(number):
def button():
global user
user += str(number)
print(number, end="")
return button
oneb = build_button(1)
twob = build_button(2)
# ...
This should be functionally identical to the [number]b functions you have above.

Python: Button command + '&'

I got an error at this code:
The error is in my function settings() in the Button() command. but I don't got any plan how to fix it, sorry. I can't put the 3 commands in an external function, cause it wouldn't get the variables...
from turtle import *
from tkinter import *
reset()
hastrail = 1
def moveup():
setheading(90)
forward(5)
def movedown():
setheading(270)
forward(5)
def moveright():
setheading(0)
forward(5)
def moveleft():
setheading(180)
forward(5)
def turnleft():
left(18)
def turnright():
right(18)
def forw():
forward(5)
def backw():
backward(5)
def trailrem():
global hastrail
if hastrail == 1:
penup()
hastrail = 0
else:
pendown()
hastrail = 1
def settings():
color(str(colorchooser.askcolor(title = "Change a line color")[1]),str(colorchooser.askcolor(title = "Change a fill color")[1]))
tk = Tk ()
tk.resizable(0,0)
tk.title("Shape, Shapesize, Pensize")
tk.geometry("400x90")
listbox = Listbox(tk)
listbox.place(x=0,y=0,width=200,height=90)
listbox.insert(1,"arrow")
listbox.insert(2,"turtle")
listbox.insert(3,"circle")
listbox.insert(4,"square")
listbox.insert(5,"triangle")
shsi = Scale(tk,width = 10,orient = HORIZONTAL)
shsi.place(x=200,y=0,width=200,height=30)
trsi = Scale(tk,width = 10, orient = HORIZONTAL)
trsi.place(x=200,y=30,width=200,height=30)
Button(tk,text="Save",command = lambda:shape(str(listbox.get(ACTIVE)))&shapesize(int(shsi.get()))&pensize(int(trsi.get()))).place(x=200,y=60,width=200,height=30)
onkeypress(moveup,"Up")
onkeypress(movedown,"Down")
onkeypress(moveright,"Right")
onkeypress(moveleft,"Left")
onkeypress(turnleft,"a")
onkeypress(turnright,"d")
onkeypress(forw,"w")
onkeypress(backw,"s")
onkeypress(trailrem,"t")
onkeypress(settings,"c")
listen()
mainloop()
Pls tell me what I've done wrong // fix it pls.
If you're trying to string together multiple expressions using the & operator, it isn't likely to work well, unless all of your function calls return integers, which isn't the case here. I don't recommend it, but you can put each command as a separate element of a collection such as a list or tuple:
Button(tk,text="Save",command = lambda:[
shape(str(listbox.get(ACTIVE))),
shapesize(int(shsi.get())),
pensize(int(trsi.get()))
]).place(x=200,y=60,width=200,height=30)
I can't put the 3 commands in an external function, cause it wouldn't get the variables
Ordinarily, this is true. But if you define the second function inside the first, all of its variables will still be visible.
def settings():
def save_button_clicked():
shape(str(listbox.get(ACTIVE)))
shapesize(int(shsi.get()))
pensize(int(trsi.get()))
#rest of `settings` code goes here...
Button(tk,text="Save",command = save_button_clicked).place(x=200,y=60,width=200,height=30)

Categories