Cách xây dựng công cụ theo dõi chi phí bằng Python
Công cụ theo dõi chi phí là một công cụ thiết yếu giúp các cá nhân và doanh nghiệp quản lý các giao dịch tài chính của họ. Với trình theo dõi chi phí, bạn có thể tạo ngân sách, phân loại chi phí và phân tích các mô hình chi tiêu.
Khám phá các phương pháp xây dựng ứng dụng giao diện đồ họa người dùng (GUI) đa nền tảng để theo dõi chi phí bằng ngôn ngữ lập trình Python.
Mô-đun Tkinter, CSV và Matplotlib
Để xây dựng ứng dụng theo dõi chi phí này, cần sử dụng thư viện Tkinter, CSV và Matplotlib.
Tkinter cho phép các nhà phát triển tạo ra các ứng dụng máy tính để bàn hấp dẫn bằng cách cung cấp một loạt các thành phần đồ họa linh hoạt như nút, nhãn và trường nhập văn bản. Giao diện thân thiện với người dùng của nó giúp đơn giản hóa quá trình tạo ứng dụng cho nhiều mục đích khác nhau.
Mô-đun CSV là một gói Python vốn có cung cấp các chức năng liên quan đến việc giải thích và cấu thành các tệp Giá trị được phân tách bằng dấu phẩy (CSV), được sử dụng rộng rãi để trao đổi dữ liệu giữa các ứng dụng và hệ thống khác nhau do tính đơn giản và khả năng tương thích với nhiều nền tảng khác nhau.
Matplotlib là một công cụ mạnh mẽ để tạo các biểu diễn trực quan động, bao gồm đồ thị, sơ đồ và biểu đồ, có thể được nâng cao hơn nữa bằng cách kết hợp nó với OpenCV để đạt được kiến thức chuyên môn về các kỹ thuật xử lý hình ảnh nâng cao.
Để cài đặt các mô-đun này, hãy chạy:
pip install tk matplotlib
Xác định cấu trúc của ứng dụng theo dõi chi phí
Nguồn gốc của mã nguồn của dự án này nằm trong kho lưu trữ GitHub được chỉ định của nó, đóng vai trò là kho lưu trữ kỹ thuật số cho tất cả các tệp và tài liệu liên quan.
Để bắt đầu, chúng tôi nhập các mô-đun bắt buộc. Sau đó, chúng tôi thiết lập một lớp có tên ExpenseTrackerApp
, lớp này đặt ra tiêu đề và kích thước của ứng dụng. Tiếp theo, chúng tôi xác định một cặp danh sách có thứ tự; một cái chứa tất cả các khoản chi tiêu được ghi lại, trong khi cái kia bao gồm các loại tiền tệ khác nhau. Một biến chuỗi, có tên là Category\_var
, cũng được thiết lập, với cài đặt ban đầu tương ứng với danh mục hàng đầu trong danh sách của chúng tôi. Cuối cùng, chúng tôi gọi thủ tục create\_widgets
để đưa ra giao diện người dùng đồ họa.
import tkinter as tk
from tkinter import ttk, messagebox, simpledialog
import csv
import matplotlib.pyplot as plt
class ExpenseTrackerApp(tk.Tk):
def __init__(self):
super().__init__()
self.title("Expense Tracker")
self.geometry("1300x600")
self.expenses = []
self.categories = [
"Food",
"Transportation",
"Utilities",
"Entertainment",
"Other",
]
self.category_var = tk.StringVar(self)
self.category_var.set(self.categories[0])
self.create_widgets()
Phương thức create\_widgets
đóng vai trò là thành phần thiết yếu trong việc xây dựng giao diện người dùng trong các ứng dụng. Để thiết lập khung hiển thị thông tin liên quan đến chi phí, chúng tôi phải tạo các yếu tố trực quan bao gồm các khung chứa các chi tiết cụ thể liên quan đến các hồ sơ này. Cụ thể, chúng tôi sẽ phát triển sáu tiện ích nhãn riêng biệt; mỗi cái được thiết kế để trình bày dữ liệu liên quan như tiêu đề, giá trị tiền tệ, mô tả, danh mục, ngày tháng và tổng số. Điều quan trọng là chỉ định phần tử gốc cho mỗi nhãn đồng thời chỉ định văn bản và đặc điểm kiểu chữ tương ứng của chúng.
Để tạo giao diện với ba kiểu nhập văn bản và menu thả xuống, hãy thiết lập kết nối giữa kiểu nhập sau và một biến có tên cate\_var
. Bắt đầu bằng cách xác định bố cục cho từng thành phần này; chỉ định kiểu và kích thước phông chữ tương ứng của chúng như sau: 1. Tạo ba tiện ích Mục nhập và gán cho chúng các vùng chứa chính riêng lẻ, các tùy chọn kiểu dáng và các giới hạn về chiều rộng.2. Xây dựng tiện ích Combobox, xác định vùng chứa chính của nó, danh sách các lựa chọn có sẵn, kiểu phông chữ và thông số kích thước.3. Liên kết Combobox với biến cate\_var
, từ đó đảm bảo rằng lựa chọn trong menu thả xuống cập nhật theo thời gian thực dựa trên tương tác của người dùng.
def create_widgets(self):
self.label = tk.Label(
self, text="Expense Tracker", font=("Helvetica", 20, "bold")
)
self.label.pack(pady=10)
self.frame_input = tk.Frame(self)
self.frame_input.pack(pady=10)
self.expense_label = tk.Label(
self.frame_input, text="Expense Amount:", font=("Helvetica", 12)
)
self.expense_label.grid(row=0, column=0, padx=5)
self.expense_entry = tk.Entry(
self.frame_input, font=("Helvetica", 12), width=15
)
self.expense_entry.grid(row=0, column=1, padx=5)
self.item_label = tk.Label(
self.frame_input, text="Item Description:", font=("Helvetica", 12)
)
self.item_label.grid(row=0, column=2, padx=5)
self.item_entry = tk.Entry(self.frame_input, font=("Helvetica", 12), width=20)
self.item_entry.grid(row=0, column=3, padx=5)
self.category_label = tk.Label(
self.frame_input, text="Category:", font=("Helvetica", 12)
)
self.category_label.grid(row=0, column=4, padx=5)
self.category_dropdown = ttk.Combobox(
self.frame_input,
textvariable=self.category_var,
values=self.categories,
font=("Helvetica", 12),
width=15,
)
self.category_dropdown.grid(row=0, column=5, padx=5)
self.date_label = tk.Label(
self.frame_input, text="Date (YYYY-MM-DD):", font=("Helvetica", 12)
)
self.date_label.grid(row=0, column=6, padx=5)
self.date_entry = tk.Entry(self.frame_input, font=("Helvetica", 12), width=15)
self.date_entry.grid(row=0, column=7, padx=5)
Tạo giao diện người dùng với các thành phần sau: Nút có nhãn “Thêm chi phí” để thêm chi phí vào danh sách; Nút có nhãn “Chỉnh sửa chi phí” để chỉnh sửa chi phí hiện có trong danh sách; Nút có nhãn “Xóa chi phí” để xóa một chi phí từ danh sách; Nút có nhãn “Tiết kiệm chi phí” giúp lưu tất cả các chi phí trong danh sách; Nút có nhãn “Hiển thị biểu đồ chi phí” hiển thị biểu đồ chi phí trong danh sách;Khung xung quanh các nút này có tiêu đề “Trình quản lý chi phí ”.
Kết hợp chức năng tạo thanh cuộn dọc được đặt ở phía bên phải khu vực nội dung chính của GUI, cho phép điều hướng nội dung liền mạch trong hộp danh sách. Sử dụng các kỹ thuật đệm thích hợp, đảm bảo trình bày hình ảnh tối ưu. Hơn nữa, khi cập nhật toàn bộ nhãn với thông tin mới, hãy thực hiện mọi điều chỉnh cần thiết để duy trì tính nhất quán trên giao diện.
self.add_button = tk.Button(self, text="Add Expense", command=self.add_expense)
self.add_button.pack(pady=5)
self.frame_list = tk.Frame(self)
self.frame_list.pack(pady=10)
self.scrollbar = tk.Scrollbar(self.frame_list)
self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
self.expense_listbox = tk.Listbox(
self.frame_list,
font=("Helvetica", 12),
width=70,
yscrollcommand=self.scrollbar.set,
)
self.expense_listbox.pack(pady=5)
self.scrollbar.config(command=self.expense_listbox.yview)
self.edit_button = tk.Button(
self, text="Edit Expense", command=self.edit_expense
)
self.edit_button.pack(pady=5)
self.delete_button = tk.Button(
self, text="Delete Expense", command=self.delete_expense
)
self.delete_button.pack(pady=5)
self.save_button = tk.Button(
self, text="Save Expenses", command=self.save_expenses
)
self.save_button.pack(pady=5)
self.total_label = tk.Label(
self, text="Total Expenses:", font=("Helvetica", 12)
)
self.total_label.pack(pady=5)
self.show_chart_button = tk.Button(
self, text="Show Expenses Chart", command=self.show_expenses_chart
)
self.show_chart_button.pack(pady=5)
self.update_total_label()
Xác định chức năng của Trình theo dõi chi phí
Kết hợp đoạn mã đã cho vào giao diện của ứng dụng hiện có làm phương tiện ghi lại chi tiêu với các danh mục và ngày được chỉ định, sau đó xác thực dữ liệu đã nhập sẽ được thêm vào danh sách động được hiển thị trong giao diện người dùng đồ họa, sau đó loại bỏ mọi nghĩa vụ nhập dữ liệu thủ công khác khỏi người dùng cuối.
Nếu không, cần hiển thị thông báo cho biết rằng các giá trị “chi phí” và “ngày” không được để trống. Sau đó, lệnh gọi hàm tới update\_total\_label sẽ được thực thi.
def add_expense(self):
expense = self.expense_entry.get()
item = self.item_entry.get()
category = self.category_var.get()
date = self.date_entry.get()
if expense and date:
self.expenses.append((expense, item, category, date))
self.expense_listbox.insert(
tk.END, f"{expense}-{item}-{category} ({date})"
)
self.expense_entry.delete(0, tk.END)
self.item_entry.delete(0, tk.END)
self.date_entry.delete(0, tk.END)
else:
messagebox.showwarning("Warning", "Expense and Date cannot be empty.")
self.update_total_label()
Để sửa đổi một khoản chi phí hiện có trong cơ sở dữ liệu hồ sơ, người ta có thể triển khai một phương thức có tên là “edit\_expense”. Phương pháp này sẽ lấy chỉ mục của bản ghi đã chọn và lấy chi phí tương ứng của nó. Tiếp theo, nó sẽ nhắc người dùng nhập giá trị mới cho chi phí thông qua hộp thoại. Nếu người dùng cung cấp một chi phí mới, phương pháp sẽ cập nhật danh sách chi phí với thông tin này. Cuối cùng, phương thức này gọi hàm “refresh\_list” cũng như chương trình con “update\_total\_label” để đảm bảo rằng tất cả các thay đổi được phản ánh chính xác trong ứng dụng.
def edit_expense(self):
selected_index = self.expense_listbox.curselection()
if selected_index:
selected_index = selected_index[0]
selected_expense = self.expenses[selected_index]
new_expense = simpledialog.askstring(
"Edit Expense", "Enter new expense:", initialvalue=selected_expense[0]
)
if new_expense:
self.expenses[selected_index] = (
new_expense,
selected_expense[1],
selected_expense[2],
selected_expense[3],
)
self.refresh_list()
self.update_total_label()
Để triển khai chức năng được mô tả trong đoạn mã đã cho, chúng tôi sẽ xác định một phương thức có tên delete\_expense
để truy xuất chỉ mục của bản ghi đã chọn và nhận chi phí tương ứng. Sau đó chúng ta sẽ chuyển chỉ mục này cho hàm để có thể xóa nó khỏi hộp danh sách. Sau đó, chúng ta sẽ gọi hàm update\_total\_label
để đảm bảo rằng tổng nhãn được cập nhật tương ứng.
def delete_expense(self):
selected_index = self.expense_listbox.curselection()
if selected_index:
selected_index = selected_index[0]
del self.expenses[selected_index]
self.expense_listbox.delete(selected_index)
self.update_total_label()
Chắc chắn! Dưới đây là ví dụ về cách bạn có thể triển khai điều này trong Python bằng cách sử dụng Flask và SQLAlchemy:pythonfrom jar import gfrom sqlalchemy import create_engine, Column, Integer, String, ForeignKeyfrom sqlalchemy.orm import sessionmaker, Relationsfrom datetime import datetimeclass User(db.Model): tablename=‘users’id=Cột(‘id’, Integer, Primary_key=True)name=Cột(’name’, String)email=Cột(’email’, String)created_at=Column(‘created_at’, DateTime, default=datetime.utcnow)updated_at=Cột(‘updated_at’, DateTime, onupdate=datetime.utcnow)
def refresh_list(self):
self.expense_listbox.delete(0, tk.END)
for expense, item, category, date in self.expenses:
self.expense_listbox.insert(
tk.END, f"{expense}-{item}-{category} ({date})"
)
Để tinh chỉnh văn bản được cung cấp, tôi sẽ cần thêm ngữ cảnh về những gì bạn muốn tôi làm với đoạn mã này. Tuy nhiên, đây là nỗ lực của tôi nhằm làm cho văn bản nhất định nghe có vẻ phức tạp hơn:pythondef update_total_label(expenses):total=sum(expenses)return Totaldef save_expenses(filename=“expenses.csv”, cost=None):if not cost:expenses=[ ]# Mở tệp CSV đã chỉ định hoặc tạo một tệp nếu nó không tồn tạitry:với open(filename, “w”) as f:writer=csv.writer(f)# Viết tiêu đề rowwriter.writerow([…])
def update_total_label(self):
total_expenses = sum(float(expense[0]) for expense in self.expenses)
self.total_label.config(text=f"Total Expenses: USD {total_expenses:.2f}")
def save_expenses(self):
with open("expenses.csv", "w", newline="") as csvfile:
writer = csv.writer(csvfile)
column_headers = ["Expense Amount", "Item Description", "Category", "Date"]
writer.writerow(column_headers)
for expense in self.expenses:
writer.writerow(expense))
Để trực quan hóa việc phân bổ chi tiêu hàng tháng theo nhiều danh mục khác nhau, chúng ta có thể triển khai một phương thức có tên show\_expenses\_chart
lấy danh sách chi phí
làm đầu vào. Đầu tiên, hãy định nghĩa một từ điển có tên cate\_totals
, nó sẽ đóng vai trò là bộ đếm để tích lũy tổng chi phí cho từng danh mục chi tiêu. Chúng ta sẽ lặp lại các mục trong danh sách chi phí
, chuyển đổi từng khoản chi phí từ chuỗi sang số thực. Đối với mỗi danh mục, nếu nó có trong từ điển cate\_totals
, chúng tôi sẽ thêm giá trị khóa của nó vào tổng số hiện có; nếu không, chúng tôi sẽ tạo một cặp khóa-giá trị mới đại diện cho số tiền chi phí hiện tại.
def show_expenses_chart(self):
category_totals = {}
for expense, _, category, _ in self.expenses:
try:
amount = float(expense)
except ValueError:
continue
category_totals[category] = category_totals.get(category, 0) \+ amount
Để tạo một biểu diễn trực quan về phân bổ chi phí theo phân loại trong tập dữ liệu, người ta có thể sử dụng hàm pie
của matplotlib. Chức năng này cho phép tạo biểu đồ hình tròn dựa trên số tiền chi phí nhất định và danh mục tương ứng của chúng. Bằng cách đặt các tham số khác nhau như autopct
, bằng
và tiêu đề của biểu đồ, người dùng có thể tùy chỉnh cách xuất hiện của đầu ra cuối cùng.
categories = list(category_totals.keys())
expenses = list(category_totals.values())
plt.figure(figsize=(8, 6))
plt.pie(
expenses, labels=categories, autopct="%1.1f%%", startangle=140, shadow=True
)
plt.axis("equal")
plt.title(f"Expense Categories Distribution (USD)")
plt.show()
Tận dụng các khả năng của lớp ExpenseTrackerApp bằng cách khởi tạo phiên bản của nó, sau đó kích hoạt vòng lặp sự kiện Tkinter bằng phương thức mainloop(), phương thức này duy trì giám sát liên tục các tương tác của người dùng cho đến khi đóng giao diện đồ họa.
if __name__ == "__main__":
app = ExpenseTrackerApp()
app.mainloop()
Kiểm tra các tính năng khác nhau của Trình theo dõi chi phí Python
Sau khi thực hiện chương trình, giao diện người dùng đồ họa (GUI) sẽ được khởi chạy, bao gồm các trường đầu vào để ghi lại các chi tiết thích hợp liên quan đến chi tiêu như mô tả mục, danh mục và ngày tháng, ngoài các hộp văn bản để nhập các giá trị số. Bằng cách nhập thông tin này và nhấp vào nút “Thêm chi phí”, người ta có thể mong đợi rằng một mục mới sẽ được thêm vào hộp danh sách. Hơn nữa, chương trình liên tục cập nhật tổng hợp tất cả các chi phí được ghi lại để thuận tiện cho bạn.
Sau khi chọn một mục chi phí cụ thể, vui lòng nhấp vào nút “Chỉnh sửa Chi phí” để bắt đầu quá trình chỉnh sửa. Thao tác này sẽ xuất hiện một hộp thoại cho phép bạn sửa đổi chi tiết của mục chi tiêu cá nhân đã chọn trong bối cảnh hiện tại của nó.
Xóa bản ghi chi phí cụ thể bằng cách nhấp vào nút “Xóa chi phí”, thao tác này sẽ xóa mục đã chọn khỏi danh sách chi phí.
Khi nhấp vào nút “Hiển thị biểu đồ chi phí”, phần mềm sẽ tạo biểu đồ dưới dạng biểu đồ hình tròn minh họa sự phân bổ chi tiêu theo các danh mục khác nhau, kèm theo tên và tỷ lệ phần trăm tương ứng.
Cải thiện Trình theo dõi chi phí
Để nâng cao trải nghiệm người dùng, có thể kết hợp chức năng tìm kiếm cho phép các cá nhân xác định các khoản chi tiêu cụ thể theo mô tả, giá trị, phân loại hoặc ngày tháng của chúng. Ngoài ra, bạn có thể cung cấp các tùy chọn để sắp xếp và lọc các bản ghi dữ liệu. Sẽ rất có ích nếu điều chỉnh ứng dụng để phù hợp với nhiều ngôn ngữ và kiểu tiền tệ khác nhau.
Hãy cân nhắc việc kết hợp chức năng thông báo vào ứng dụng, cho phép người dùng thiết lập các ngưỡng kích hoạt cảnh báo khi bị vi phạm. Những cảnh báo này có thể đóng vai trò như một cảnh báo chống bội chi và giúp xác định các khoản chi tiêu bất thường.