Website-Suche

Lernen Sie die Grundlagen von Python: Lassen Sie uns einen einfachen Ausgaben-Tracker erstellen.


Wenn Sie jemals versucht haben, ein Budget zu erstellen, wissen Sie, wie schwierig es sein kann, einen Ausgaben-Tracker zu finden, der das tut, was Sie wollen. Aber wie wäre es, wenn Sie einen selbst erstellen? Lassen Sie uns die Grundlagen von Python lernen, indem wir einen einfachen Ausgaben-Tracker erstellen, den Sie tatsächlich verwenden können.

Festlegung der Anforderungen unserer Ausgabenverfolgungs-App

Als ich auf diese Idee kam, wollte ich eine App erstellen, die mehr ist als nur eine weitere Kommandozeilen-Terminal-App. Wir haben ein paar davon gebaut (wie die einfache To-Do-Liste mit Python). Für diese wollte ich eine grafische Benutzeroberfläche verwenden, also habe ich beschlossen, dass wir die Tkinter-Bibliothek importieren, um einige benutzbare UI-Elemente zu haben.

Bibliotheken ermöglichen es uns, Code wiederzuverwenden. Es gibt normalerweise eine Bibliothek für die meisten Dinge, die Sie in Python tun möchten. Das Importieren dieser Bibliotheken vermeidet es, den gesamten Code, den sie enthalten, von Grund auf neu zu schreiben.

In dieser App werden wir implementieren:

  • Ausgabenbuchung
  • Ein Budget festlegen
  • Den Vergleich unserer Ausgaben mit unserem Budget
  • Sp spendinghistorie anzeigen

Am Ende dieses Kurses werden wir eine gute Vorstellung davon haben, wie Python funktioniert, und in der Lage sein, unsere erste GUI-basierte Python-App abzuschließen.

Einrichten unseres Projekts

Sie sollten überprüfen, ob auf Ihrem Gerät Python installiert ist, indem Sie die Python-Version überprüfen. Ich habe bereits erklärt, wie man meine Lieblings-IDE (Visual Studio) mit Python verbindet. Sobald Sie die Installation von Python auf Ihrem Gerät und das Aktualisieren auf die aktuelle Version hinter sich gebracht haben, können wir damit beginnen, ein neues Projekt zu erstellen.

Ich habe Python für dieses Projekt gewählt, weil es eine der einfachsten Sprachen für Anfänger ist. Lassen Sie uns mit dem Aufbau unseres Ausgabenverfolgers beginnen!

Erstellen des Hauptanwendungsfensters

Da wir uns in dieser Anwendung von der Konsole entfernen werden, müssen wir stattdessen Tkinter einrichten, um die grafische Benutzeroberfläche (GUI) unserer Anwendung zu erstellen. Das Design der Benutzeroberfläche in Python kann komplex sein, daher halte ich es einfach und erkläre dir nur, was der Code, den ich dir gebe, bewirkt. So wird mein UI-Fenster definiert. Wir beginnen mit dem Import von Tkinter:

import tkinter as tk
from tkinter import ttk, messagebox, simpledialog

Tkinter enthält alle Funktionen, die wir benötigen, um eine grundlegende Benutzeroberfläche zu erstellen. Sie werden bemerken, dass wir auch Ttk importieren, eine Themen-Engine innerhalb von Tkinter. Dies ermöglicht es uns, das Aussehen unserer Benutzeroberfläche nach Wunsch zu steuern. Wir werden auch messagebox und simpledialog verwenden, um den Benutzer nach den anfänglichen Budgeteinstellungen zu fragen. Außerdem möchten wir monatliche Daten speichern, falls wir in Zukunft darauf zugreifen möchten, daher fügen wir auch oben in unserer Datei hinzu:

import json
from datetime import datetime

Abgesehen davon, dass es sehr nah an meinem eigenen Namen ist, ist JSON tatsächlich ziemlich cool als Serialisierungssystem. Glücklicherweise ist es standardmäßig in Python enthalten, sodass wir es direkt importieren können. Der Import von datetime hilft uns, unsere Daten im gesamten Anwendung richtig zu formatieren.

Jetzt, da wir die Importe herausgefunden haben, lass uns das Fenster tatsächlich bauen:

def create_widgets(self):
    Main Frame
    main_frame = ttk.Frame(self.root, padding="10")
    main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
    Expense Input Frame
    input_frame = ttk.LabelFrame(main_frame, text="Add Expense", padding="10")
    input_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), padx=5, pady=5)
    ttk.Label(input_frame, text="Date (YYYY-MM-DD):").grid(row=0, column=0, sticky=tk.W)
    self.date_entry = ttk.Entry(input_frame)
    self.date_entry.grid(row=0, column=1, padx=5, pady=2)
    ttk.Label(input_frame, text="Category:").grid(row=1, column=0, sticky=tk.W)
    self.category_combobox = ttk.Combobox(input_frame, values=self.categories)
    self.category_combobox.grid(row=1, column=1, padx=5, pady=2)
    ttk.Label(input_frame, text="Amount:").grid(row=2, column=0, sticky=tk.W)
    self.amount_entry = ttk.Entry(input_frame)
    self.amount_entry.grid(row=2, column=1, padx=5, pady=2)
    ttk.Button(input_frame, text="Add Expense", command=self.add_expense).grid(row=3, column=0, columnspan=2, pady=5)
    Category Management Frame
    category_frame = ttk.LabelFrame(main_frame, text="Manage Categories", padding="10")
    category_frame.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), padx=5, pady=5)
    self.new_category_entry = ttk.Entry(category_frame)
    self.new_category_entry.grid(row=0, column=0, padx=5, pady=2)
    ttk.Button(category_frame, text="Add Category", command=self.add_category).grid(row=0, column=1, padx=5, pady=2)

Diese Einträge gestalten nur unser Fenster. Wenn Sie möchten, können Sie mit den Zahlen herumspielen und sehen, was dabei herauskommt, da das Herumfummeln mit ihnen harmlos ist (abgesehen davon, dass das endgültige Fenster schrecklich aussieht). Wir müssen auch den Rahmen und die Schaltfläche 'Speichern' anzeigen und das Gitter so konfigurieren, dass es ansprechend aussieht:

 Display Frame
 display_frame = ttk.LabelFrame(main_frame, text="Expenses and Budget", padding="10")
 display_frame.grid(row=0, column=1, rowspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), padx=5, pady=5)
 self.expense_tree = ttk.Treeview(display_frame, columns=('Date', 'Category', 'Amount'), show='headings')
 self.expense_tree.heading('Date', text='Date')
 self.expense_tree.heading('Category', text='Category')
 self.expense_tree.heading('Amount', text='Amount')
 self.expense_tree.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
 scrollbar = ttk.Scrollbar(display_frame, orient=tk.VERTICAL, command=self.expense_tree.yview)
 scrollbar.grid(row=0, column=1, sticky=(tk.N, tk.S))
 self.expense_tree.configure(yscrollcommand=scrollbar.set)
 self.budget_label = ttk.Label(display_frame, text=f"Monthly Budget: ${self.monthly_budget:.2f}")
 self.budget_label.grid(row=1, column=0, sticky=tk.W, pady=2)
 self.total_expenses_label = ttk.Label(display_frame, text="Total Expenses: $0.00")
 self.total_expenses_label.grid(row=2, column=0, sticky=tk.W, pady=2)
 self.remaining_budget_label = ttk.Label(display_frame, text=f"Remaining Budget: ${self.monthly_budget:.2f}")
 self.remaining_budget_label.grid(row=3, column=0, sticky=tk.W, pady=2)
 Save Button
 ttk.Button(display_frame, text="Save Data", command=self.save_data).grid(row=4, column=0, pady=10)
 Configure grid
 self.root.columnconfigure(0, weight=1)
 self.root.rowconfigure(0, weight=1)
 main_frame.columnconfigure(1, weight=1)
 main_frame.rowconfigure(0, weight=1)
 display_frame.columnconfigure(0, weight=1)
 display_frame.rowconfigure(0, weight=1)

Wie Sie sehen können, erfordert die Benutzeroberfläche eine ganze Menge an Programmierung, um sie richtig zu gestalten. Da Sie jedoch planen, die Grundlagen von Python zu lernen, ist das Verständnis des UI-Designs Teil des Ganzen. Jetzt, da wir die Benutzeroberfläche eingerichtet und am Laufen haben, lassen Sie uns an der Funktionalität arbeiten.

Kategorien definieren und Ausgaben hinzufügen

Um unserer App ein wenig "Körper" zu geben, habe ich ein paar Ausgabenkategorien vordefiniert. Ich habe diese als Überschriften zusammen mit dem Rest unserer Definitionen eingefügt:

class ExpenseTrackerApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Expense Tracker & Budget Planner")
        self.root.geometry("1100x500")
        self.expenses = []
        self.categories = ["Rent", "Food", "Entertainment", "Car", "Credit Cards"]
        
        self.monthly_budget = self.get_initial_budget()
        
        self.create_widgets()
    def get_initial_budget(self):
        while True:
            budget = simpledialog.askfloat("Monthly Budget", "Enter your monthly budget:", minvalue=0.01)
            if budget is not None:
                return budget
            else:
                if messagebox.askyesno("No Budget", "You haven't entered a budget. Do you want to exit?"):
                    self.root.quit()
                    return 0

Definitionen wie diese sollten am Anfang unseres Programms stehen. Zu diesem Zweck sollte dieser Code-Ausschnitt vor dem Widget-Erstellungscode kommen, den wir bereits entwickelt haben.

Die Funktion get_initial_budget(self) erstellt beim Start der Anwendung ein Popup, um Daten zu sammeln, die den Betrag des verfügbaren Geldes bestimmen. Das Nichteingeben eines Wertes führt dazu, dass die App sofort beendet wird.

Wir benötigen auch eine Funktion, um Ausgaben hinzuzufügen und Kategorien mit neuen, benutzerdefinierten zu aktualisieren. Glücklicherweise ist dies ebenfalls einfach umzusetzen:

def add_expense(self):
    try:
        date = self.date_entry.get()
        category = self.category_combobox.get()
        amount = float(self.amount_entry.get())
        self.expenses.append({
            'date': date,
            'category': category,
            'amount': amount
        })
        self.update_expense_list()
        self.update_budget_info()
        self.clear_input_fields()
    except ValueError:
        messagebox.showerror("Error", "Invalid input. Please check your entries.")
def add_category(self):
    new_category = self.new_category_entry.get().strip()
    if new_category and new_category not in self.categories:
        self.categories.append(new_category)
        self.category_combobox['values'] = self.categories
        self.new_category_entry.delete(0, tk.END)
        messagebox.showinfo("Category Added", f"'{new_category}' has been added to the categories.")
    else:
        messagebox.showerror("Error", "Invalid category name or category already exists.")

Um unsere grundlegende Funktionalität abzurunden, benötigen wir Funktionen, um die Ausgabenliste zu aktualisieren, wenn wir eine neue Ausgabe eingeben. Wir benötigen eine Hilfsfunktion, um das Kombinationsfeld zu leeren, nachdem wir die Daten eingegeben haben. Und schließlich müssen wir berechnen, wie viel von unserem Budget noch verfügbar ist. Dieser einfache Code-Schnipsel ermöglicht uns genau das:

def update_expense_list(self):
    for item in self.expense_tree.get_children():
        self.expense_tree.delete(item)
    for expense in self.expenses:
        self.expense_tree.insert('', 'end', values=(
            expense['date'],
            expense['category'],
            f"${expense['amount']:.2f}"
        ))
def update_budget_info(self):
    total_expenses = sum(expense['amount'] for expense in self.expenses)
    remaining_budget = self.monthly_budget - total_expenses
    self.total_expenses_label.config(text=f"Total Expenses: ${total_expenses:.2f}")
    self.remaining_budget_label.config(text=f"Remaining Budget: ${remaining_budget:.2f}")
def clear_input_fields(self):
    self.date_entry.delete(0, tk.END)
    self.category_combobox.set('')
    self.amount_entry.delete(0, tk.END)

Nachdem wir all diese Daten eingegeben haben, wie stellen wir sicher, dass wir sie nicht verlieren? Ich habe eine einfache Speicherfunktion implementiert, die das JSON-Format verwendet, das wir zuvor importiert haben:

def save_data(self):
    data = {
        'budget': self.monthly_budget,
        'categories': self.categories,
        'expenses': self.expenses
    }
    
    Get the current date to use in the filename
    current_date = datetime.now().strftime("%Y-%m")
    default_filename = f"expense_data_{current_date}.json"
    
    file_path = filedialog.asksaveasfilename(
        defaultextension=".json",
        filetypes=[("JSON files", "*.json")],
        initialfile=default_filename
    )
    
    if file_path:
        with open(file_path, 'w') as f:
            json.dump(data, f, indent=2)
        messagebox.showinfo("Save Successful", f"Data saved to {file_path}")

Diese Funktion serialisiert die Daten und speichert sie an einem bestimmten Dateispeicherort mit dem aktuellen Datum, das dem Dateinamen angehängt wird. Das letzte, was wir tun müssen, ist, die Schleife der main() Funktion zusammenzustellen:

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

Das sollte es unserem Ausgabenverfolgungssystem ermöglichen, problemlos zu laufen. Herzlichen Glückwunsch zum Abschluss deiner ersten GUI-basierten Anwendung in Python!

Ergänzungen, Mängel und Anpassungen

Nachdem Sie dies abgeschlossen haben, verstehen Sie ein wenig, wie Tkinter funktioniert und wie Sie es zur Erstellung von GUIs nutzen können. Wenn Sie ein wenig CSS oder Grafikdesign Kenntnisse haben, sollten Sie schnell herausfinden, wie Sie Tkinter verwenden können. Wenn Sie ein paar Herausforderungen möchten, könnten Sie als Nächstes Folgendes ausprobieren:

  • Erstellen oder verwenden Sie ein neues Thema für Ihre App.
  • Erstelle eine "Lade"-Funktion und einen Button dafür. Ich habe die Ladefunktion absichtlich weggelassen, um dir mehr Spielraum zum Erkunden zu geben.
  • Erforschen Sie, wie Sie eine graphisch basierte Analyse Ihres Budgets als Kuchendiagramm erstellen können.

Die endgültige Anwendung sollte derzeit ungefähr so aussehen:

Wo geht es von hier aus weiter?

Dieses Entwicklungstutorial hat Ihnen nur einen groben Überblick über Tkinter gegeben, aber wenn Sie planen, mehr GUI-basierte Apps zu erstellen, müssen Sie ein besseres Verständnis dafür entwickeln, was es tun kann. RealPython kann Ihnen eine Vorstellung davon geben, wie Sie Tkinter oder eines der anderen verfügbaren GUI-Frameworks oder Toolkits verwenden. Python ist auf einer grundlegenden Ebene ziemlich leicht zu verstehen, aber es gibt so viel zu entdecken, während Sie die Grundlagen von Python lernen. Das einzige, was Ihre Kreativität bei dem, was Sie erstellen können, einschränkt, ist Ihre Vorstellungskraft.

Wenn Sie beim Code stecken bleiben und mein vollständiges Python-Skript zum Vergleichen mit Ihrem haben möchten, ist es auf meinem GitHub verfügbar.