Contents

Jak zbudować narzędzie do śledzenia wydatków w Pythonie?

Narzędzie do śledzenia wydatków jest niezbędnym narzędziem, które pomaga osobom fizycznym i firmom zarządzać ich transakcjami finansowymi. Dzięki narzędziu do śledzenia wydatków można tworzyć budżety, kategoryzować wydatki i analizować wzorce wydatków.

Poznaj metody tworzenia wieloplatformowej aplikacji z graficznym interfejsem użytkownika (GUI) do śledzenia wydatków przy użyciu języka programowania Python.

Moduły Tkinter, CSV i Matplotlib

W celu skonstruowania tej aplikacji do śledzenia wydatków konieczne jest wykorzystanie bibliotek Tkinter, CSV i Matplotlib.

Tkinter umożliwia programistom tworzenie atrakcyjnych aplikacji desktopowych, zapewniając szereg wszechstronnych komponentów graficznych, takich jak przyciski, etykiety i pola wprowadzania tekstu. Jego przyjazny dla użytkownika interfejs upraszcza proces tworzenia aplikacji do różnych celów.

Moduł CSV to nieodłączny pakiet Pythona, który oferuje funkcje związane z interpretacją i tworzeniem plików CSV (Comma-Separated Value), które są szeroko wykorzystywane do wymiany danych między różnymi aplikacjami i systemami ze względu na ich prostotę i kompatybilność z różnymi platformami.

Matplotlib to potężne narzędzie do tworzenia dynamicznych reprezentacji wizualnych, w tym wykresów, wykresów i wykresów, które można dodatkowo ulepszyć, łącząc je z OpenCV, aby zdobyć wiedzę na temat zaawansowanych technik manipulacji obrazem.

Aby zainstalować te moduły, uruchom:

pip install tk matplotlib 

Define the Structure of the Expense Tracker App

Pochodzenie kodu źródłowego tego projektu znajduje się w wyznaczonym repozytorium GitHub, które służy jako cyfrowy depozyt dla wszystkich powiązanych plików i dokumentacji.

Aby rozpocząć, importujemy moduły imperatywne. Następnie tworzymy klasę o nazwie ExpenseTrackerApp , która określa tytuł i wymiary aplikacji. Następnie definiujemy uporządkowaną parę list; jedna zawiera wszystkie zarejestrowane wydatki, podczas gdy druga obejmuje różne kategorie pieniężne. Tworzona jest również zmienna łańcuchowa o nazwie category_var , z początkowym ustawieniem odpowiadającym pierwszej kategorii na naszej liście. Na koniec wywołujemy procedurę create_widgets w celu stworzenia graficznego interfejsu użytkownika.

 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()

Metoda create_widgets służy jako istotny element w konstruowaniu interfejsów użytkownika w aplikacjach. Aby ustanowić ramy do wyświetlania informacji związanych z wydatkami, musimy wygenerować elementy wizualne składające się z ramek, które zawierają określone szczegóły związane z tymi rekordami.W szczególności opracujemy sześć oddzielnych widżetów etykiet; każdy przeznaczony do prezentacji odpowiednich danych, takich jak nagłówki, wartości pieniężne, opisy, kategorie, daty i ogólne sumy. Kluczowe jest przypisanie elementu nadrzędnego dla każdej etykiety, przy jednoczesnym określeniu ich odpowiednich tekstów i cech typograficznych.

Aby utworzyć interfejs z trzema wejściami tekstowymi i menu rozwijanym, należy ustanowić połączenie między tym ostatnim a zmienną o nazwie category_var . Rozpocznij od zdefiniowania układu dla każdego z tych elementów; określ ich odpowiednie style czcionek i wymiary w następujący sposób:1. Utwórz trzy widżety Entry i przypisz im indywidualne kontenery nadrzędne, opcje stylizacji i ograniczenia szerokości.2. Skonstruuj widżet Combobox, zdefiniuj jego kontener nadrzędny, listę dostępnych wyborów, styl czcionki i specyfikacje wymiarowe.3. Powiąż Combobox ze zmienną category_var , zapewniając w ten sposób, że wybór w menu rozwijanym będzie aktualizowany w czasie rzeczywistym w oparciu o interakcję użytkownika.

     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) 

Utwórz interfejs użytkownika z następującymi komponentami:Przycisk o nazwie “Add Expense”, który dodaje wydatek do listy;Przycisk o nazwie “Edit Expense”, który edytuje istniejący wydatek na liście;Przycisk o nazwie “Delete Expense”, który usuwa wydatek z listy;Przycisk o nazwie “Save Expenses”, który zapisuje wszystkie wydatki na liście;Przycisk o nazwie “Show Expenses Chart”, który wyświetla wykres wydatków na liście;Ramka otaczająca te przyciski z tytułem “Expense Manager”.

Włącz funkcjonalność tworzenia pionowego paska przewijania, który jest umieszczony po prawej stronie głównego obszaru zawartości GUI, umożliwiając płynną nawigację po zawartości w polu listy. Wykorzystanie odpowiednich technik wypełniania zapewnia optymalną prezentację wizualną. Ponadto, po zaktualizowaniu całkowitej etykiety o nowe informacje, wykonaj wszelkie niezbędne korekty, aby zachować spójność w całym interfejsie.

         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() 

Zdefiniuj funkcjonalność narzędzia do śledzenia wydatków

Włącz podany fragment kodu do interfejsu istniejącej aplikacji jako sposób rejestrowania wydatków z określonymi kategoriami i datami, po czym walidacja wprowadzonych danych jest dodawana do dynamicznej listy wyświetlanej w graficznym interfejsie użytkownika, a następnie usuwa wszelkie dalsze obowiązki ręcznego wprowadzania danych przez użytkownika końcowego.

W przeciwnym razie konieczne jest wyświetlenie powiadomienia wskazującego, że wartości “wydatku” i “daty” nie mogą być puste. Następnie należy wykonać wywołanie funkcji update\_total\_label.

     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() 

Aby zmodyfikować istniejący wydatek w bazie danych rekordów, można zaimplementować metodę o nazwie “edit\_expense”.Ta metoda pobierze indeks wybranego rekordu i uzyska odpowiadający mu wydatek. Następnie poprosi użytkownika o wprowadzenie nowej wartości wydatku w oknie dialogowym. Jeśli użytkownik poda nowy wydatek, metoda zaktualizuje listę wydatków o te informacje. Na koniec metoda wywołuje funkcję “refresh\_list”, a także podprogram “update\_total\_label”, aby upewnić się, że wszystkie zmiany są dokładnie odzwierciedlone w aplikacji.

     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() 

Aby zaimplementować funkcjonalność opisaną w podanym fragmencie kodu, zdefiniujemy metodę o nazwie delete_expense , która pobiera indeks wybranego rekordu i pobiera odpowiadający mu wydatek. Następnie przekażemy ten indeks do funkcji, aby można go było usunąć z pola listy. Następnie wywołamy funkcję update_total_label , aby upewnić się, że łączna etykieta zostanie odpowiednio zaktualizowana.

     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() 

Jasne! Oto przykład, jak można to zaimplementować w Pythonie przy użyciu Flask i SQLAlchemy:pythonfrom flask import gfrom sqlalchemy import create_engine, Column, Integer, String, ForeignKeyfrom sqlalchemy.orm import sessionmaker, relationshipfrom datetime import datetimeclass User(db.Model): tablename = ‘users’id = Column(‘id’, Integer, primary_key=True)name = Column(’name’, String)email = Column(’email’, String)created_at = Column(‘created_at’, DateTime, default=datetime.utcnow)updated_at = Column(‘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})"
            ) 

Aby dopracować dostarczony tekst, będę potrzebował więcej kontekstu na temat tego, co chcesz, abym zrobił z tym fragmentem kodu. Oto jednak moja próba nadania podanemu tekstowi bardziej wyrafinowanego brzmienia:pythondef update_total_label(expenses):total = sum(expenses)return totaldef save_expenses(filename=“expenses.csv”, expenses=None):if not expenses:expenses = []# Otwórz podany plik CSV lub utwórz go, jeśli nie istniejetry:with open(filename, “w”) as f:writer = csv.writer(f)# Write the header 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)) 

Aby zwizualizować rozkład miesięcznych wydatków w różnych kategoriach, możemy zaimplementować metodę o nazwie show_expenses_chart , która przyjmuje jako dane wejściowe listę wydatków . Najpierw zdefiniujmy słownik o nazwie category_totals , który będzie służył jako licznik do gromadzenia całkowitych wydatków dla każdej kategorii wydatków. Będziemy iterować po wpisach na liście expenses , konwertując każdą kwotę wydatku z łańcucha na liczbę zmiennoprzecinkową.Dla każdej kategorii, jeśli jest ona obecna w słowniku category_totals , dodamy jej wartość klucza do istniejącej sumy; w przeciwnym razie utworzymy nową parę klucz-wartość reprezentującą bieżącą kwotę wydatków.

     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 

Aby stworzyć wizualną reprezentację kategorycznego rozkładu wydatków w zbiorze danych, można wykorzystać funkcję pie matplotlib. Funkcja ta umożliwia wygenerowanie wykresu kołowego na podstawie podanych kwot wydatków i odpowiadających im kategorii. Ustawiając różne parametry, takie jak autopct , equal i tytuł wykresu, użytkownicy mogą dostosować sposób wyświetlania końcowego wyniku.

         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() 

Wykorzystaj możliwości klasy ExpenseTrackerApp, tworząc jej instancję, a następnie aktywując pętlę zdarzeń Tkinter za pomocą metody mainloop(), która utrzymuje ciągłe monitorowanie interakcji użytkownika do momentu zamknięcia interfejsu graficznego.

 if __name__ == "__main__":
    app = ExpenseTrackerApp()
    app.mainloop() 

Testowanie różnych funkcji Python Expense Tracker

Po uruchomieniu programu uruchomiony zostanie graficzny interfejs użytkownika (GUI), zawierający pola wejściowe do rejestrowania istotnych szczegółów dotyczących wydatków, takich jak opis przedmiotu, kategoria i data, a także pola tekstowe do wprowadzania wartości liczbowych. Po wpisaniu tych informacji i kliknięciu przycisku “Dodaj wydatek” można oczekiwać, że nowy wpis zostanie dołączony do pola listy. Co więcej, dla wygody użytkownika program stale aktualizuje sumę wszystkich zarejestrowanych wydatków.

/pl/images/adding-entries-to-expense-tracker.jpg

Po wybraniu konkretnego wydatku należy kliknąć przycisk “Edytuj wydatki”, aby rozpocząć proces edycji. Spowoduje to wyświetlenie okna dialogowego umożliwiającego modyfikację szczegółów wybranej pozycji wydatków w istniejącym kontekście.

/pl/images/selecting-and-editing-expense.jpg

Usunięcie określonego rekordu wydatków poprzez kliknięcie przycisku “Usuń wydatki”, co spowoduje usunięcie wybranej pozycji z listy wydatków.

/pl/images/selecting-and-deleting-expense.jpg

Po kliknięciu przycisku “Pokaż wykres wydatków” oprogramowanie generuje graficzną reprezentację w postaci wykresu kołowego, który ilustruje rozkład wydatków w różnych kategoriach, wraz z ich odpowiednimi nazwami i wartościami procentowymi.

/pl/images/pie-chart-of-expenses.jpg

Ulepszanie narzędzia do śledzenia wydatków

W celu zwiększenia komfortu użytkowania możliwe jest włączenie funkcji wyszukiwania, która umożliwia użytkownikom zlokalizowanie określonych wydatków według ich opisu, wartości, klasyfikacji lub dat.Dodatkowo można zapewnić opcje sortowania i filtrowania rekordów danych. Korzystne byłoby dostosowanie aplikacji do różnych języków i stylów walutowych.

Rozważ włączenie funkcji powiadomień do aplikacji, umożliwiając użytkownikom ustalenie progów, które uruchamiają alerty po ich przekroczeniu. Alerty te mogą służyć jako ostrzeżenie przed nadmiernymi wydatkami i pomóc w identyfikacji nieregularnych wydatków.