Mundo em Python

Controle de Gastos (usando CRUD Tkinter)

import tkinter as tk
from tkinter import ttk, messagebox
import sqlite3
from datetime import datetime
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
def Database():
global conn, cursor
conn = sqlite3.connect("Gastos.db")
cursor = conn.cursor()
cursor.execute(
"CREATE TABLE IF NOT EXISTS REGISTRATION (RID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, DESCRICAO TEXT, DATA TEXT, AMOUNT REAL)")
conn.commit()
def DisplayForm():
global tree, SEARCH, descrição, data, amount
root = tk.Tk()
root.geometry("900x600")
root.title("Controle de Gastos") # Set default date to today's date
today_date = datetime.now().strftime('%Y-%m-%d') SEARCH = tk.StringVar()
descrição = tk.StringVar()
data = tk.StringVar(value=today_date) # Set the default value to today's date
amount = tk.DoubleVar() TopViewForm = tk.Frame(root, width=600, bd=1, relief=tk.SOLID)
TopViewForm.pack(side=tk.TOP, fill=tk.X) LFrom = tk.Frame(root, width="350", bg="#15244C")
LFrom.pack(side=tk.LEFT, fill=tk.Y) LeftViewForm = tk.Frame(root, width=500, bg="#0B4670")
LeftViewForm.pack(side=tk.LEFT, fill=tk.Y) MidViewForm = tk.Frame(root, width=600)
MidViewForm.pack(side=tk.RIGHT) tk.Label(LFrom, text="Descrição ", font=("Arial", 12), bg="#15244C", fg="white").pack(side=tk.TOP)
tk.Entry(LFrom, font=("Arial", 10, "bold"), textvariable=descrição).pack(side=tk.TOP, padx=10, fill=tk.X) tk.Label(LFrom, text="Data ", font=("Arial", 12), bg="#15244C", fg="white").pack(side=tk.TOP)
tk.Entry(LFrom, font=("Arial", 10, "bold"), textvariable=data).pack(side=tk.TOP, padx=10, fill=tk.X) tk.Label(LFrom, text="Quantidade ", font=("Arial", 12), bg="#15244C", fg="white").pack(side=tk.TOP)
tk.Entry(LFrom, font=("Arial", 10, "bold"), textvariable=amount).pack(side=tk.TOP, padx=10, fill=tk.X) tk.Button(LFrom, text="Submeter", font=("Arial", 10, "bold"), bg="cyan", command=register).pack(side=tk.TOP,
padx=10, pady=5,
fill=tk.X) lbl_txtsearch = tk.Label(LeftViewForm, text="Descrição", font=('verdana', 10), bg="#0B4670")
lbl_txtsearch.pack()
search = tk.Entry(LeftViewForm, textvariable=SEARCH, font=('verdana', 15), width=10)
search.pack(side=tk.TOP, padx=10, fill=tk.X) btn_search = tk.Button(LeftViewForm, text="Pesquisar", bg="cyan", command=SearchRecord)
btn_search.pack(side=tk.TOP, padx=10, pady=10, fill=tk.X) btn_view = tk.Button(LeftViewForm, text="Ver tudo", bg="cyan", command=DisplayData)
btn_view.pack(side=tk.TOP, padx=10, pady=10, fill=tk.X) btn_Limpar = tk.Button(LeftViewForm, text="Limpar", bg="cyan", command=limpar)
btn_Limpar.pack(side=tk.TOP, padx=10, pady=10, fill=tk.X) btn_apagar = tk.Button(LeftViewForm, text="Apagar", bg="cyan", command=apagar)
btn_apagar.pack(side=tk.TOP, padx=10, pady=10, fill=tk.X) btn_actualizar = tk.Button(LeftViewForm, text="Atualizar", bg="cyan", command=actualizacao)
btn_actualizar.pack(side=tk.TOP, padx=10, pady=10, fill=tk.X) btn_plot = tk.Button(LeftViewForm, text="Visualizar Gráfico", bg="cyan", command=plot_data)
btn_plot.pack(side=tk.TOP, padx=10, pady=10, fill=tk.X) scrollbarx = tk.Scrollbar(MidViewForm, orient=tk.HORIZONTAL)
scrollbary = tk.Scrollbar(MidViewForm, orient=tk.VERTICAL) tree = ttk.Treeview(MidViewForm, columns=("RID", "Descrição", "Data", "Quantidade"),
selectmode="extended", height=100, yscrollcommand=scrollbary.set, xscrollcommand=scrollbarx.set) scrollbary.config(command=tree.yview)
scrollbary.pack(side=tk.RIGHT, fill=tk.Y) scrollbarx.config(command=tree.xview)
scrollbarx.pack(side=tk.BOTTOM, fill=tk.X) tree.heading('RID', text="ID", anchor=tk.W)
tree.heading('Descrição', text="Descrição", anchor=tk.W)
tree.heading('Data', text="Data", anchor=tk.W)
tree.heading('Quantidade', text="Quantidade", anchor=tk.W) tree.column('#0', stretch=tk.NO, minwidth=0, width=0)
tree.column('#1', stretch=tk.NO, minwidth=0, width=50)
tree.column('#2', stretch=tk.NO, minwidth=0, width=100)
tree.column('#3', stretch=tk.NO, minwidth=0, width=150)
tree.column('#4', stretch=tk.NO, minwidth=0, width=100) tree.pack()
tree.bind("<Double-1>", OnDoubleClick) DisplayData()
root.mainloop()
def register():
Database()
vdescricao = descrição.get()
vdata = data.get()
vamount = amount.get() if vdescricao == '' or vdata == '' or vamount == 0:
messagebox.showinfo("Atenção", "Preencha os espaços vazios!!!")
return

try:
datetime.strptime(vdata, '%Y-%m-%d')
except ValueError:
messagebox.showerror("Erro", "Formato de data inválido. Use AAAA-MM-DD.")
return

conn.execute('INSERT INTO REGISTRATION (DESCRICAO, DATA, AMOUNT) VALUES (?, ?, ?)',
(vdescricao, vdata, vamount))
conn.commit()
messagebox.showinfo("Sucesso", "Registro adicionado com sucesso")
DisplayData()
conn.close()
def SearchRecord():
Database()
if SEARCH.get() != "":
tree.delete(*tree.get_children())
cursor = conn.execute("SELECT * FROM REGISTRATION WHERE DESCRICAO LIKE ?", ('%' + str(SEARCH.get()) + '%',))
fetch = cursor.fetchall()
for data in fetch:
tree.insert('', 'end', values=(data))
cursor.close()
conn.close()
def actualizacao():
Database()
vdescricao = descrição.get()
vdata = data.get()
vamount = amount.get() if vdescricao == '' or vdata == '' or vamount == 0:
messagebox.showinfo("Atenção", "Preencha todos os espaços!!!")
return

try:
datetime.strptime(vdata, '%Y-%m-%d')
except ValueError:
messagebox.showerror("Erro", "Formato de data inválido. Use AAAA-MM-DD.")
return

curItem = tree.focus()
contents = (tree.item(curItem))
selecteditem = contents['values']
conn.execute('UPDATE REGISTRATION SET DESCRICAO=?, DATA=?, AMOUNT=? WHERE RID = ?',
(vdescricao, vdata, vamount, selecteditem[0]))
conn.commit()
messagebox.showinfo("Mensagem", "Atualizado com sucesso")
limpar()
DisplayData()
conn.close()
def apagar():
Database()
if not tree.selection():
messagebox.showwarning("Atenção", "Selecione o gasto a ser apagado")
else:
result = messagebox.askquestion('Confirmar', 'Deseja apagar o gasto selecionado?', icon="warning")
if result == 'yes':
curItem = tree.focus()
contents = (tree.item(curItem))
selecteditem = contents['values']
tree.delete(curItem)
conn.execute("DELETE FROM REGISTRATION WHERE RID = ?", (selecteditem[0],))
conn.commit()
messagebox.showinfo("Sucesso", "Gasto apagado com sucesso")
conn.close()
def limpar():
tree.delete(*tree.get_children())
DisplayData()
SEARCH.set("")
descrição.set("")
data.set(datetime.now().strftime('%Y-%m-%d')) # Reset to today's date
amount.set(0.0)
def DisplayData():
Database()
tree.delete(*tree.get_children())
cursor = conn.execute("SELECT * FROM REGISTRATION")
fetch = cursor.fetchall()
cursor.close()
conn.close()
for data in fetch:
tree.insert('', 'end', values=(data))
def OnDoubleClick(event):
curItem = tree.focus()
contents = (tree.item(curItem))
selecteditem = contents['values']
descrição.set(selecteditem[1])
data.set(selecteditem[2])
amount.set(selecteditem[3])
def plot_data():
Database()
cursor = conn.execute("SELECT DATA, AMOUNT FROM REGISTRATION")
data = cursor.fetchall()
cursor.close()
conn.close() if not data:
messagebox.showinfo("Informação", "Não há dados para plotar.")
return

dates = [datetime.strptime(record[0], '%Y-%m-%d') for record in data]
amounts = [record[1] for record in data] fig, ax = plt.subplots()
ax.plot(dates, amounts, marker='o') ax.set_xlabel("Data")
ax.set_ylabel("Quantidade")
ax.set_title("Gastos ao longo do tempo")
fig.autofmt_xdate() plot_window = tk.Toplevel()
plot_window.title("Gráfico de Gastos") canvas = FigureCanvasTkAgg(fig, master=plot_window)
canvas.draw()
canvas.get_tk_widget().pack()
if __name__ == '__main__':
DisplayForm()
0