How To Create a Banking Application in Python Tkinter
In this Python Tutorial we will see How to Create a simple banking app using Python Tkinter.
In this python tkinter bank project we will create custom panels, buttons and chart, with Real-time balance tracking, Transaction history with visual indicators, Input validation and error handling, Charts showing balance trends .
What We Are Gonna Use In This Project:
- Python Tkinter: Core GUI framework.- ttkbootstrap: theme system.
- matplotlib: Data visualization for balance history charts.
- NumPy: Numerical operations for chart data.
- Visual Studio Editor.
- Visual Studio Editor.
Project Source Code:
- Build the user interface
def create_widgets(self):
"""
Create and arrange all widgets for the application.
"""
# Main frame to hold all other widgets
main_frame = ttk.Frame(self.root, padding="10 10 10 10")
main_frame.pack(fill=tk.BOTH, expand=True)
# Header frame for logo and date
header_frame = ttk.Frame(main_frame)
header_frame.pack(fill=tk.X, pady=(0, 20))
# Logo
logo_label = ttk.Label(header_frame, text="PyBank",
font=("Roboto", 24, "bold"), foreground=ACCENT_COLOR)
logo_label.pack(side=tk.LEFT)
# Current date display
date_label = ttk.Label(header_frame,
text=datetime.datetime.now().strftime("%B %d, %Y"),
font=("Roboto", 12))
date_label.pack(side=tk.RIGHT)
# Content area to hold balance, input, and chart
content_frame = ttk.Frame(main_frame)
content_frame.pack(fill=tk.BOTH, expand=True)
# Balance display card
balance_frame = ttk.Frame(content_frame, style="Card.TFrame")
balance_frame.grid(row=0, column=0, padx=(0, 10), pady=(0, 10), sticky="nsew")
balance_title = ttk.Label(balance_frame, text="Current Balance",
font=("Roboto", 16, "bold"), foreground=ACCENT_COLOR)
balance_title.pack(pady=(10, 5))
self.balance_label = ttk.Label(balance_frame, text="$0.00",
font=("Roboto", 28, "bold"),
foreground=SECONDARY_ACCENT)
self.balance_label.pack(pady=(0, 10))
# Transaction input frame
input_frame = ttk.Frame(content_frame, style="Card.TFrame")
input_frame.grid(row=1, column=0, padx=(0, 10), pady=(0, 10), sticky="nsew")
amount_label = ttk.Label(input_frame, text="Transaction Amount",
font=("Roboto", 14))
amount_label.pack(pady=(10, 5))
self.amount_entry = ttk.Entry(input_frame, font=("Roboto", 14))
self.amount_entry.pack(pady=(0, 10), padx=10, fill=tk.X)
button_frame = ttk.Frame(input_frame)
button_frame.pack(pady=(0, 10), fill=tk.X)
# Custom styled buttons for deposit and withdraw
deposit_btn = ttb.Button(button_frame, text="Deposit",
bootstyle=(SUCCESS, SOLID),
command=lambda: self.handle_transaction("deposit"))
deposit_btn.pack(side=tk.LEFT, padx=(10, 5), fill=tk.X, expand=True)
withdraw_btn = ttb.Button(button_frame, text="Withdraw",
bootstyle=(DANGER, SOLID),
command=lambda: self.handle_transaction("withdraw"))
withdraw_btn.pack(side=tk.RIGHT, padx=(5, 10), fill=tk.X, expand=True)
# Chart area for balance history
self.chart_frame = ttk.Frame(content_frame, style="Card.TFrame")
self.chart_frame.grid(row=0, column=1, rowspan=2, padx=(10, 0),
pady=(0, 10), sticky="nsew")
chart_title = ttk.Label(self.chart_frame, text="Balance History",
font=("Roboto", 16, "bold"),
foreground=ACCENT_COLOR)
chart_title.pack(pady=(10, 5))
self.create_chart()
# Transaction history frame
history_frame = ttk.Frame(content_frame, style="Card.TFrame")
history_frame.grid(row=2, column=0, columnspan=2, sticky="nsew")
history_title = ttk.Label(history_frame, text="Transaction History",
font=("Roboto", 16, "bold"),
foreground=ACCENT_COLOR)
history_title.pack(pady=(10, 5))
# Frame to hold the Treeview and scrollbar
tree_frame = ttk.Frame(history_frame)
tree_frame.pack(pady=(0, 10), padx=10, fill=tk.BOTH, expand=True)
# Create the Treeview for transaction history
self.history_tree = ttk.Treeview(tree_frame,
columns=("Type", "Amount", "Date"),
show="headings", height=8)
self.history_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
# Add a vertical scrollbar to the Treeview
scrollbar = ttk.Scrollbar(tree_frame, orient="vertical",
command=self.history_tree.yview)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
self.history_tree.configure(yscrollcommand=scrollbar.set)
# Configure Treeview columns
self.history_tree.heading("Type", text="Type")
self.history_tree.heading("Amount", text="Amount")
self.history_tree.heading("Date", text="Date")
self.history_tree.column("Type", width=100)
self.history_tree.column("Amount", width=100)
self.history_tree.column("Date", width=150)
# Apply custom styles to the Treeview
self.style_treeview()
# Configure grid weights for responsive layout
content_frame.grid_columnconfigure(0, weight=1)
content_frame.grid_columnconfigure(1, weight=1)
content_frame.grid_rowconfigure(2, weight=1)
- Custom Table Styling.
def style_treeview(self):
"""
Apply custom styles to the Treeview widget.
"""
# Configure a modern style for the Treeview
self.style.configure("Treeview",
background="white",
foreground=TEXT_COLOR,
rowheight=30,
fieldbackground="white")
self.style.map('Treeview', background=[('selected', ACCENT_COLOR)])
# Style the Treeview headings
self.style.configure("Treeview.Heading",
background="#EDF2F7",
foreground=TEXT_COLOR,
relief="flat",
font=("Roboto", 11, "bold"))
self.style.map("Treeview.Heading",
background=[('active', '#E2E8F0')])
# Configure tags for deposit and withdraw rows
self.history_tree.tag_configure('deposit', foreground=POSITIVE_COLOR)
self.history_tree.tag_configure('withdraw', foreground=NEGATIVE_COLOR)
- Data Visualization Setup.
def create_chart(self):
"""
Create and initialize the balance history chart.
"""
# Create a chart
fig, self.ax = plt.subplots(figsize=(5, 3), facecolor=BACKGROUND_COLOR)
# Create a FigureCanvasTkAgg object and add it to the chart frame
self.canvas = FigureCanvasTkAgg(fig, master=self.chart_frame)
self.canvas.draw()
self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
# Set the background color of the axis to match the app's background
self.ax.set_facecolor(BACKGROUND_COLOR)
# Style the x and y axis tick labels
self.ax.tick_params(axis='x', colors=TEXT_COLOR)
self.ax.tick_params(axis='y', colors=TEXT_COLOR)
# Style the chart border
for spine in self.ax.spines.values():
spine.set_color('#E2E8F0')
# Initial update of the chart
self.update_chart()
- Dynamic Chart Updates.
def update_chart(self):
"""
Update the balance history chart with current transaction data.
"""
# Clear the previous plot
self.ax.clear()
# Initialize balances list with starting balance of 0
balances = [0]
# Calculate balance history
if len(self.transactions) > 0:
for transaction in self.transactions:
if transaction.type == "deposit":
balances.append(balances[-1] + transaction.amount)
else:
balances.append(balances[-1] - transaction.amount)
# Create x-axis values (transaction indices)
x = range(len(balances))
# Plot the balance history line
self.ax.plot(x, balances, color=ACCENT_COLOR, linewidth=2,
marker='o', markersize=6)
# Fill the area under the line
gradient = np.linspace(0, 1, len(x))
self.ax.fill_between(x, balances, color="red", alpha=0.2)
# Add labels and title
self.ax.set_xlabel('Transactions', color=TEXT_COLOR)
self.ax.set_ylabel('Balance', color=TEXT_COLOR)
#self.ax.set_title('Balance History', color=ACCENT_COLOR, fontweight='bold')
# Style the grid
self.ax.grid(color='#E2E8F0', linestyle='--', linewidth=0.5, alpha=0.7)
# Remove top and right spines
self.ax.spines['right'].set_visible(False)
# Add subtle shadow to the line
shadow_line, = self.ax.plot(x, balances, color='grey',
linewidth=6, alpha=0.2)
shadow_line.set_zorder(self.ax.get_zorder() - 1)
# Add data labels
for i, balance in enumerate(balances):
self.ax.annotate(f'${balance:.2f}', (i, balance),
textcoords="offset points",
xytext=(0,10), ha='center',
fontsize=8, color=TEXT_COLOR)
# Adjust layout and redraw the canvas
plt.tight_layout()
self.canvas.draw()
- Processes both deposit and withdrawal requests with validation and error handling.
def handle_transaction(self, type):
"""
Process a deposit or withdrawal transaction.
"""
try:
amount = float(self.amount_entry.get())
if amount <= 0:
self.show_error("Please enter a valid positive number")
return
if type == "withdraw" and amount > self.balance:
self.show_error("Insufficient funds")
return
if type == "deposit":
self.balance += amount
self.show_success(f"Successfully deposited ${amount:.2f}")
else:
self.balance -= amount
self.show_success(f"Successfully withdrew ${amount:.2f}")
# Add the new transaction to the list
self.transactions.append(Transaction(type, amount))
# Update UI elements
self.update_balance_label()
self.update_history()
self.update_chart()
self.amount_entry.delete(0, tk.END) # Clear the entry field
except ValueError:
self.show_error("Please enter a valid number")
- Updates the prominently displayed current balance whenever the account balance changes.
def update_balance_label(self):
"""
Update the displayed balance.
"""
self.balance_label.config(text=f"${self.balance:.2f}")
- Refreshes the transaction history table with the latest transactions.
def update_history(self):
"""
Update the transaction history display.
"""
# Clear existing entries
for i in self.history_tree.get_children():
self.history_tree.delete(i)
# Add transactions to the Treeview
for transaction in reversed(self.transactions):
if transaction.type == "deposit":
icon = "↑" # Up arrow for deposit
tag = 'deposit'
else:
icon = "↓" # Down arrow for withdraw
tag = 'withdraw'
self.history_tree.insert("", "end", values=(
f"{icon} {transaction.type.capitalize()}",
f"${transaction.amount:.2f}",
transaction.date.strftime("%Y-%m-%d %H:%M")
), tags=(tag,))
# Apply alternating row colors
for i, item in enumerate(self.history_tree.get_children()):
if i % 2 == 0:
self.history_tree.item(item,
tags=self.history_tree.item(item, "tags") + ('evenrow',))
else:
self.history_tree.item(item,
tags=self.history_tree.item(item, "tags") + ('oddrow',))
# Configure tag colors
self.history_tree.tag_configure('evenrow', background='#F7FAFC')
self.history_tree.tag_configure('oddrow', background='#EDF2F7')
- Creates and displays custom-styled error dialogs when invalid actions are attempted.
def show_error(self, message):
"""
Display an error message to the user.
"""
# Create custom error dialog instead of using ttkbootstrap's Messagebox
error_dialog = tk.Toplevel(self.root)
error_dialog.title("Error")
error_dialog.geometry("450x170")
error_dialog.configure(bg="white")
error_dialog.resizable(False, False)
# Make dialog modal
error_dialog.transient(self.root)
error_dialog.grab_set()
# Center the dialog on the parent window
x = self.root.winfo_x() + (self.root.winfo_width() / 2) - (450 / 2)
y = self.root.winfo_y() + (self.root.winfo_height() / 2) - (170 / 2)
error_dialog.geometry(f"+{int(x)}+{int(y)}")
# Add error icon and message
frame = ttk.Frame(error_dialog)
frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)
error_label = ttk.Label(frame, text="⊘ Error", font=("Arial", 17, "bold"),
foreground=NEGATIVE_COLOR)
error_label.pack(pady=(0, 10))
message_label = ttk.Label(frame, text=message, font=("Arial", 14, ""),
wraplength=400)
message_label.pack(pady=(0, 10))
ok_button = tk.Button(frame, text="OK", bg=ACCENT_COLOR, fg="white", width=10,
command=error_dialog.destroy)
ok_button.pack()
- Shows confirmation dialogs when transactions are successfully completed.
def show_success(self, message):
"""
Display a success message to the user.
"""
# Create custom success dialog
success_dialog = tk.Toplevel(self.root)
success_dialog.title("Success")
success_dialog.geometry("450x170")
success_dialog.configure(bg="white")
success_dialog.resizable(False, False)
# Make dialog modal
success_dialog.transient(self.root)
success_dialog.grab_set()
# Center the dialog on the parent window
x = self.root.winfo_x() + (self.root.winfo_width() / 2) - (450 / 2)
y = self.root.winfo_y() + (self.root.winfo_height() / 2) - (170 / 2)
success_dialog.geometry(f"+{int(x)}+{int(y)}")
# Add success icon and message
frame = ttk.Frame(success_dialog)
frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)
success_label = ttk.Label(frame, text="✓ Success", font=("Arial", 17, "bold"),
foreground=SECONDARY_ACCENT)
success_label.pack(pady=(0, 10))
message_label = ttk.Label(frame, text=message, font=("Arial", 14, ""),
wraplength=400)
message_label.pack(pady=(0, 10))
ok_button = tk.Button(frame, text="OK", bg=SECONDARY_ACCENT, fg="white",
width=10, command=success_dialog.destroy)
ok_button.pack()
if you want the source code click on the download button below
disclaimer: you will get the source code and to make it work in your machine is your responsibility and to debug any error/exception is your responsibility this project is for the students who want to see an example and read the code not to get and run.
Download Projects Source Code








