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.
Related
I am having a hard time figuring out how to update selected references of a method from vscode. Right-clicking on the method name doesn't give the options to choose and update the references. New to Python and vscode and trying to figure out the nuances around it. Can some help me with this please!
Here are the classes - I have a class Player_Account
class Player_Account:
def __init__(self,owner,balance):
self.owner = owner
self.balance = balance
def deposit(self,balance):
self.balance += balance
return "Amount added to players pot !"
def withdraw(self,amount): # I need to update this method name to withdraw_amount
if self.balance<amount:
return "Funds Unavailable"
else:
self.balance -= amount
return "Money added to hand !"
def __str__(self):
return f"Account owner : {self.owner} has outstanding balance of {self.balance}"
Another class Player
class Player:
def __init__(self,name):
self.name=name
self.hand = []
self.player_account:Player_Account = Player_Account(name,0)
def initial_money(self,amount):
self.player_account.balance = amount
def player_won_the_hand(self,amount):
self.player_account.deposit(amount)
return True
def player_betting_amount_for_the_round(self,amount):
value = self.player_account.withdraw(amount) # I need this reference to be automatically updated as well
if value == 'Funds Unavailable':
return False
else:
return True
I just tried.
set cursor on def withdraw
press F2 (rename symbol)
change name to withdraw_amount and press Enter
it takes a few seconds but both are changed
I use PyLance.
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")
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)
I'm converting an old tkinter program to wxPython. One of the things from tk that I used liberally was tk.IntVar() and the like. Is there anything in wx that provides similar functionality?
Specifically, I'd like to be able to define module-level variables such as myvar = tk.StringVar(). Then when those variables are updated, have one or more UI elements update based on the new variable value just like what would happen with:
self.score = tk.Entry(self, textvariable=myvar.get())
here is how you would normally organize your app .... globals tend to be a bad idea
class MyNestedPanel(wx.Panel):
def __init__(self,*a,**kw):
...
self.user = wx.TextCtrl(self,-1)
def SetUser(self,username):
self.user.SetValue(username)
class MyMainPanel(wx.Panel):
def __init__(self,*a,**kw):
...
self.userpanel = MyNestedPanel(self,...)
def SetUsername(self,username):
self.userpanel.SetUser(username)
class MainFrame(wx.Frame):
def __init__(self,*a,**kw):
...
self.mainpanel = MyMainPanel(self,...)
def SetUsername(self,username):
self.mainpanel.SetUsername(username)
a = wx.App()
f = MainFrame(...)
f.Show()
a.MainLoop()
although you can make helper functions
def set_widget_value(widget,value):
if hasattr(widget,"SetWidgetValue"):
return widget.SetWidgetValue(value)
if isinstance(widget,wx.Choice):
return widget.SetStringSelection(value)
if hasattr(widget,"SetValue"):
return widget.SetValue(value)
if hasattr(widget,"SetLabel"):
return widget.SetLabel(value)
else:
raise Exception("Unknown Widget Type : %r"%widget)
def get_widget_value(widget):
if hasattr(widget,"GetWidgetValue"):
return widget.GetWidgetValue()
if isinstance(widget,wx.Choice):
return widget.GetStringSelection()
if hasattr(widget,"GetValue"):
return widget.GetValue()
if hasattr(widget,"GetLabel"):
return widget.GetLabel()
else:
raise Exception("Unknown Widget Type : %r"%widget)
class WidgetManager(wx.Panel):
def __init__(self,parent):
self._parent = parent
wx.Panel.__init__(self,parent,-1)
self.CreateWidgets()
def CreateWidgets(self):
#create all your widgets here
self.widgets = {}
def SetWidgetValue(self,value):
if isinstance(value,dict):
for k,v in value.items():
set_widget_value(self.widgets.get(k),v)
else:
raise Exception("Expected a dictionary but got %r"%value)
def GetWidgetValue(self):
return dict([(k,get_widget_value(v))for k,v in self.widgets])
and then use them like this https://gist.github.com/joranbeasley/37becd81ff2285fcc933
I've wrote an little app to scroll an stock market ticker into a Tkinter window and update the stock values every minute using a threading class.
If I closed the window the main process didn't stops, then I've implemented a method to close the window and stop the thread. But when I close the window the main process delay the stopping to the next call to the theading.run() method.
How can I get that an instant closing process?
The code:
# -*- coding: UTF-8 -*-
import tkinter as tk
import tkinter.messagebox
import time
import threading
from random import randint as randint, uniform as randlimit
# Here starts the program working process, until here was the GUI
# CONSTANTS
CHAR_UP = "\u25B2"
CHAR_DOWN = "\u25BC"
CHAR_EVEN = "="
UPDATE_TIME = 60
# INITIAL DATA, this must be changed to implement the load of a external source
stock_market = [["GOOG", "587.25", CHAR_UP, "(+12.14)"],
["AAPL", "237.14", CHAR_UP, "(+7.25)"],
["GTAT", "87.47", CHAR_DOWN, "(-1.18)"],
["KNDI", "167.32", CHAR_UP, "(+6.85)"],
["ORCL", "482.91", CHAR_DOWN, "(-24.65)"],
["FBOK", "327.67", CHAR_DOWN, "(-11.78)"],
["TWTR", "842.41", CHAR_UP, "(+15.45)"]]
class AplicationTkinter(tk.Frame):
"""
Class of tkinter.Frame subclass, Initializes the GUI
constants:
SPEED, the delay in millisecs of the scroll
attributes:
parent, the root Tk object
"""
SPEED = 250
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.parent = parent
self._initGUI()
self._scroll_ticker()
self.parent.protocol("WM_DELETE_WINDOW",self.stop)
# or toplevel.protocol(...
def _initGUI(self):
"""
initGUI, draws the layout.
"""
# changes the window icon
self.parent.iconbitmap("tabla.ico")
self.parent.title("Stock Exchange Ticker")
# fix a status bar at the bottom of the window, for future improvements
self.status_bar = tk.Label(self.parent, text="", bd=1, relief=tk.SUNKEN,
anchor=tk.W)
self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
# content Frame for entry, for future improvements
self.frame = tk.Frame(self.parent)
self.frame.pack()
self.var_entry = tk.StringVar()
self.entry = tk.Entry(self.frame, textvariable=self.var_entry)
self.entry.pack()
self.var_entry.set("a default value")
str_ent_1 = self.entry.get()
# content LabelFrame to show the ticker scrolling line of text
self.label_frame = tk.LabelFrame(self.parent,
text="Ventana de Resultados")
self.label_frame.pack()
# creates an instance of the StockMarket class for contents the data
self.market_one = StockMarket(stock_market)
# the scrolling line of Text for show the data
self.txt_ticker_widget = tk.Text(self.label_frame, background='black',
height=1, width=56, wrap="none")
self.txt_ticker_widget.pack(side=tk.TOP, fill=tk.X)
self.txt_ticker_widget.tag_configure("up", foreground="green")
self.txt_ticker_widget.tag_configure("down", foreground="red")
self.txt_ticker_widget.tag_configure("even", foreground="white")
self.tag = {CHAR_DOWN: "down", CHAR_EVEN: "even", CHAR_UP: "up"}
def _scroll_ticker(self):
"""
scroll_ticker, inserts character by character in the Text widget
"""
self.txt_ticker_widget.configure(state=tk.NORMAL)
self.txt_ticker_widget.insert(tk.END,
self.market_one.get_next_character(),
self.tag[self.market_one.get_tag()])
# TODO simplify
self.txt_ticker_widget.see(tk.END)
self.txt_ticker_widget.configure(state=tk.DISABLED)
self.txt_ticker_widget.after(self.SPEED, self._scroll_ticker)
# recursive each interval of millisecs, constant SPEED
def stop(self):
if tk.messagebox.askokcancel("Quit?", "Are you sure you want to quit?"):
# self.destroy()
print("STOPPING !!")
self.market_one.thread_updating.stop()
self.destroy()
self.parent.quit()
class StockTicker():
"""
Class StockTicker, handle each stock symbol and their data
attributes:
symbol, string, the abbreviature of the securitie
price, string, the current price of the securitie
direction, string(1), is a character that indicates its las fix price
went up, down or even
change, string, is the value of the last change surrounded by '()',
the first character is '+' or '-'
"""
def __init__(self, list_data):
self.symbol, self.price, self.direction, self.change = list_data
def update_ticker(self):
"""
update_ticker, update the securitie price, direction and
change with random values
"""
flt_price = float(self.price)
if randint(0, 9) == 0:
self.direction = CHAR_EVEN
else:
increase_percent = randlimit(-5, 5)
# TODO implementar normalvariate(0, 0.02) o gauss(0, 0.02)
flt_change = flt_price * increase_percent / 100
flt_new_price = flt_price + flt_change
self.price = "{:.2f}".format(flt_new_price)
if flt_change < 0:
self.direction = CHAR_DOWN
elif flt_change == 0:
self.direction = CHAR_EVEN
else:
self.direction = CHAR_UP
self.change = "({:+.2f})".format(flt_change)
def ticker_to_text(self):
"""
ticker_to_text, returns a formatted string with all the data of
the securitie.
"""
return " | {} {} {} {} ".format(self.symbol, self.price,
self.direction, self.change)
class StockMarket():
"""
Class StockMarket, creates and handle a list of StockTicker objects,
and provide to the GUI of stuff for the scroll ticker
attributes:
smarket, list of StockTicker objects
thread_actualizar, Thread object to update the stock market
each time interval
"""
def __init__(self, l_inicial):
self.tickers = []
self.index = 0
self._load(l_inicial)
self.current_ticker = self._get_one_ticker()
self.thread_updating = UpdateThread(self)
self.thread_updating.start()
def _load(self, l_inicial):
"""
load_market, load the list with StockTicker object taking the data from
the initial source data.
"""
for data_ticker in l_inicial:
simple_ticker = StockTicker(data_ticker)
self.tickers.append(simple_ticker)
def update_market(self):
"""
update_market, update the objects of the list
"""
for ticker in self.tickers:
ticker.update_ticker()
def _get_one_ticker(self):
"""
get_one_ticker, getter function to return one securitie data in text
format and rotates to the next one
"""
self.one_ticker = self.tickers.pop(0)
self.tickers.append(self.one_ticker)
self.index = 0
return self.one_ticker.ticker_to_text()
def get_next_character(self):
"""
get_next_character, returns a character of one securitie
(if the securitie data is exhausted retrieve another securitie)
data to the GUI.
"""
if self.index == len(self.current_ticker):
self.current_ticker = self._get_one_ticker()
self.index = 0
character_symbol = self.current_ticker[self.index:self.index+1]
self.index += 1
return character_symbol
def get_tag(self):
return self.one_ticker.direction
class UpdateThread(threading.Thread):
"""
Class UpdateThread(), subclass of Thread, handle the time to the next
update of the stock market values
args:
market_1, a StockMarket class object to update
attributes:
my_check, string for debugging purpouses, it'll be implemented the
source data management the_market, StockMarket object that will
be updated
"""
def __init__(self, market_1):
self.my_check = " CHECK " # TODO replace with initial source data.
self.the_market = market_1
self.is_quit = False
threading.Thread.__init__(self)
def run(self):
"""
run, overrides the Thread run method, and calls the update_market
method of StockMarket class each interval
"""
time.sleep(UPDATE_TIME)
self.the_market.update_market()
print(" UPDATED!!!") # for debugging
if not self.is_quit:
self.run()
def stop(self):
"""
stop, for stopping the thread when event occurs
"""
self.is_quit = True
# STARTS THE PROGRAM
def main():
the_window = tk.Tk()
aplication = AplicationTkinter(the_window)
# init the GUI process
the_window.mainloop()
if __name__ == '__main__':
main()