这是我的主要代码
import ttkbootstrap as ttk
from random import choice, choices
import csv
from Login import Login
login = Login()
login.login_gui()
user = login.authenticated_user
if user:
with open('tanishStock_data.csv') as sheet:
reader = list(csv.DictReader(sheet))
day = int(reader[-1]['Day'])
cash = float(reader[-1]['Cash'])
stocks = {"reliance":float(reader[-4]['Price']), "tata motors":float(reader[-3]['Price']), "itc":float(reader[-2]['Price']), "mahindra":float(reader[-1]['Price'])}
labels = {} #stores stock_name:it's price_label (refer to line 108)
holdings = {} #stock : {quantity, price, value}
def update_label(label, text, fg=None):
label.configure(text=text, foreground = fg)
portfolio_window = None
def bull_run(stock):
inc_or_dec = choices([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], weights=[20, 30, 10, 8, 7, 4, 3, 2, 2, 1])[0]
stocks[stock] = stocks[stock] * inc_or_dec / 100 + stocks[stock]
def bear_run(stock):
inc_or_dec = choices([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], weights=[20, 30, 10, 8, 7, 4, 3, 2, 2, 1])[0]
stocks[stock] = stocks[stock] - stocks[stock] * inc_or_dec / 100
def simulate_stocks():
for stock in stocks:
randomizer = choice(["plus", "minus"])
if randomizer == "plus":
bull_run(stock)
elif randomizer == "minus":
bear_run(stock)
else:
print("error encountered")
break
update_prices()
main_window.after(5000, simulate_stocks)
def update_prices():
for stock_name, label in labels.items():
price = float(label.cget("text")) #gets the price out of the price_label
if price > stocks[stock_name]:
update_label(label, f"{stocks[stock_name]:.2f}", fg = "red")
else:
update_label(label, f"{stocks[stock_name]:.2f}", fg = "#228B22")
def buy_stock():
global cash
stock = vvariable.get().strip().lower()
try:
quantity = int(entry_quantity_price.get())
except ValueError:
update_label(quantity_warning, "*Enter a valid quantity")
return
if stock in stocks:
total_cost = quantity * stocks[stock]
if total_cost > cash:
update_label(quantity_warning, "*Not enough cash")
elif quantity <= 0 or quantity > 10000:
update_label(quantity_warning,"*Quantity should be between 1 and 10000")
else:
update_label(quantity_warning, "")
update_label(stock_warning, "")
if stock not in holdings:
holdings[stock] = {"quantity": 0, "price": 0, "value": 0}
holdings[stock]["price"] = (stocks[stock] * quantity + holdings[stock]["price"] * holdings[stock]["quantity"])/(quantity + holdings[stock]["quantity"])
holdings[stock]["quantity"] += quantity
holdings[stock]["value"] = holdings[stock]["quantity"] * holdings[stock]["price"]
cash -= total_cost
update_label(cash_display, f"CASH: {cash:.2f}")
else:
update_label(stock_warning, "*No such stock exists")
def sell_stock():
global cash
stock = vvariable.get().strip().lower()
try:
quantity = int(entry_quantity_price.get())
except ValueError:
update_label(quantity_warning, "*Enter a valid quantity")
return
if stock in holdings:
if quantity <= 0 or quantity > holdings[stock]["quantity"]:
update_label(quantity_warning, "*Invalid quantity")
else:
update_label(quantity_warning, "")
update_label(stock_warning, "")
holdings[stock]["quantity"] -= quantity
sell_value = quantity * stocks[stock]
cash += sell_value
update_label(cash_display, f"CASH: {cash:.2f}")
holdings[stock]["value"] = holdings[stock]["quantity"] * holdings[stock]["price"]
if holdings[stock]["quantity"] == 0:
del holdings[stock]
else:
stock_warning.config(text="*You don't own this stock")
def stock_data_writer(real_day): # writes stock data in csv file
with open('tanishStock_data.csv', mode ='a', newline ='') as sheet:
writer = csv.DictWriter(sheet, fieldnames = ['Day', 'Stock', 'Price', 'Cash'])
for stock in stocks:
writer.writerow({'Day' : real_day, 'Stock' : stock, 'Price' : f'{stocks[stock]:.2f}', 'Cash' : f'{cash:.2f}'})
def day_system(): #manages day system in the stock simulator
global day
day += 1
stock_data_writer(day)
update_label(day_display, text = f"DAY : {day}", fg = "red")
main_window.after(20000, lambda: day_system())
def clickable_stocks(stockname, stockprice):
entry_stock_entry.delete(0, ttk.END)
entry_quantity_price.delete(0, ttk.END)
entry_stock_entry.insert(0, stockname)
entry_quantity_price.insert(0, stockprice)
def show_portfolio():
global portfolio_window
# Destroy the existing portfolio window if it exists
if portfolio_window:
portfolio_window.destroy()
# Create new portfolio window
portfolio_window = ttk.Toplevel(main_window)
portfolio_window.title("PORTFOLIO")
portfolio_window.geometry("420x300")
portfolio_window.resizable(False, False)
# Create canvas and scrollbar
canvas = ttk.Canvas(portfolio_window)
scrollbar = ttk.Scrollbar(portfolio_window, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=scrollbar.set)
# Create a frame inside the canvas
canvas_frame = ttk.Frame(canvas)
canvas.create_window((0, 0), window=canvas_frame, anchor="nw")
# Pack the scrollbar and canvas
scrollbar.pack(side="right", fill="y")
canvas.pack(side="left", fill="both", expand=True)
def update_portfolio_window():
# Clear the frame before updating
for widget in canvas_frame.winfo_children():
widget.destroy()
row_num = 2
cash_label = ttk.Label(canvas_frame, text=f"CASH: {cash:.2f}", font=("arial", 13, "bold"),foreground="green")
cash_label.grid(row=0, column=0, padx=10, pady=10, sticky="w")
upper_divider = ttk.Label(canvas_frame, text="_" * 80)
upper_divider.grid(row=1, column=0, columnspan=2, padx=10)
if holdings:
for stock, data in holdings.items():
stock_name = ttk.Label(canvas_frame, text=stock.title(), font=("arial", 15))
purchase_data = ttk.Label(canvas_frame,
text=f"Qty: {data['quantity']} | Price: {data['price']:.2f}",
font=("arial", 8))
current_value = ttk.Label(canvas_frame, text=f"Value: {data['value']:.2f}", font=("arial", 13),foreground="green")
stock_name.grid(row=row_num, column=0, padx=10, pady=5, sticky="w")
purchase_data.grid(row=row_num + 1, column=0, padx=10, sticky="w")
current_value.grid(row=row_num + 1, column=1, padx=10, sticky="e")
row_num += 3
else:
no_holdings_label = ttk.Label(canvas_frame, text="No holdings yet.", font=("arial", 12))
no_holdings_label.grid(row=row_num, column=0, columnspan=2, pady=50)
close_button = ttk.Button(canvas_frame, text="Close", command=portfolio_window.destroy)
close_button.grid(row=row_num + 1, column=1, sticky="e", padx=10, pady=10)
canvas_frame.update_idletasks()
canvas.config(scrollregion=canvas.bbox("all"))
update_portfolio_window()
main_window = ttk.Window(themename = "darkly")
def on_destroy():
print("Main window is being destroyed.")
main_window.destroy()
main_window.protocol("WM_DELETE_WINDOW", on_destroy)
main_window.geometry("600x500")
main_window.title("Tanish Stock Exchange")
vvariable = ttk.StringVar()
header = ttk.Label(main_window, text = "TSE", font=("arial", 20), foreground="blue")
header.pack()
day_display = ttk.Label(main_window, text = f"DAY : {day}", font = ("arial", 15), foreground='red')
day_display.place(x = 260, y = 300)
y_position = 80
stock_entry = ttk.Label(main_window, text ="STOCK: ", font=("arial", 15, "bold"))
stock_entry.place(x = 300, y = 80)
stock_warning = ttk.Label(main_window, text = "", font=("arial", 7), foreground="red")
stock_warning.place(x = 400, y=110)
stock_quantity = ttk.Label(main_window, text ="quantity: ", font=("arial", 15, "bold"))
stock_quantity.place(x = 300, y = 120)
quantity_warning = ttk.Label(main_window, text = "", font=("arial", 7), foreground="red")
quantity_warning.place(x = 400, y=150)
entry_stock_entry = ttk.Combobox(master = main_window, values = ["reliance", "tata motors", "itc", "mahindra"], textvariable = vvariable)
entry_stock_entry.place(x = 400, y = 83)
entry_quantity_price = ttk.Entry(main_window)
entry_quantity_price.place(x = 400, y = 125)
buy = ttk.Button(main_window, text="BUY", style="success", width=7, padding=(20, 10), command = buy_stock)
buy.place(x = 470, y = 170)
sell = ttk.Button(main_window, text="SELL",style="danger", width=7, padding=(20, 10), command = sell_stock)
sell.place(x = 370, y = 170)
portfolio = ttk.Button(main_window, text="Portfolio",style = "primary",padding = (20, 10),command=show_portfolio)
portfolio.place(x=20,y=20)
cash_display = ttk.Label(main_window, text = f"CASH: {cash}", font=("arial", 13, "bold"),foreground="blue")
cash_display.place(x=410, y=30)
for stock in stocks:
stock_label = ttk.Label(main_window, text=f"{stock.title()}:", font=("arial", 15, "bold"), foreground="#4682B4")
stock_label.place(x=20, y=y_position)
price_label = ttk.Label(main_window, text=f"{stocks[stock]}", font=("arial", 15), foreground="green")
price_label.place(x=150, y=y_position)
labels[stock] = price_label
stock_label.bind("<Button-1>", lambda event, stockname=stock: clickable_stocks(stockname, round(cash//float(labels[stockname].cget("text")))))
y_position += 40
simulate_stocks()
day_system()
main_window.mainloop()
您可能想知道什么是登录类,所以这里是:
import ttkbootstrap as ttk
import json
import bcrypt
import os
class Login:
def __init__(self, username=None, password=None):
self.username = username
self.password = password
self.authenticated_user = False
def __str__(self):
return "Login class made for login purposes in every project."
def display_message(self, message_label, message, color="red"):
message_label.config(text=message, foreground=color)
def authenticate_user(self, username, password, window):
self.username = username.get().strip().lower()
self.password = password.get().strip().encode("utf-8")
self.display_message(self.login_message_label, "")
try:
with open('User_data.json', 'r+') as user_data:
data = json.load(user_data)
for user in data:
if user["username"] == self.username:
if bcrypt.checkpw(self.password, user["password"].encode("utf-8")):
self.display_message(self.login_message_label, "Login successful!", "green")
window.destroy()
self.authenticated_user = True
return
else:
self.display_message(self.login_message_label, "Invalid password.")
return
salt = bcrypt.gensalt()
hashed_pass = bcrypt.hashpw(self.password, salt).decode("utf-8")
new_entry = {"username": self.username, "password": hashed_pass}
data.append(new_entry)
user_data.seek(0)
json.dump(data, user_data, indent=4)
user_data.truncate()
self.create_user_stock_file(self.username)
self.display_message(self.login_message_label, "User added successfully!", "green")
window.destroy()
self.authenticated_user = True
except FileNotFoundError:
self.display_message(self.login_message_label, "Server error")
except json.JSONDecodeError:
self.display_message(self.login_message_label, "Server error")
def create_user_stock_file(self, username):
filename = f"{username}stock.csv"
if not os.path.exists(filename):
with open(filename, 'w') as file:
file.write("StockName,Quantity,Price\n")
def login_gui(self):
login_window = ttk.Window(themename="darkly")
login_window.title("TSA Login")
login_window.geometry("400x250")
ttk.Label(login_window, text="Welcome to TSA", font=("arial", 17, "bold")).pack()
ttk.Label(login_window, text="Username: ", font=("arial", 12)).place(x=20, y=50)
login_username_entry = ttk.Entry(login_window, width=30)
login_username_entry.place(x=120, y=47)
ttk.Label(login_window, text="Password: ", font=("arial", 12)).place(x=20, y=100)
login_password_entry = ttk.Entry(login_window, show="*", width=30)
login_password_entry.place(x=120, y=97)
self.login_message_label = ttk.Label(login_window, text="", font=("arial", 10))
self.login_message_label.place(x=20, y=130)
ttk.Button(login_window, text="Login", style="primary-outline", width=13, command=lambda: self.authenticate_user(login_username_entry, login_password_entry, login_window)).place(x=160, y=160)
login_window.mainloop()
所以,当我运行主代码时,不要关注 json 或 csv 文件,我登录并成功登录,为了方便起见,我现在对 csv 文件进行了硬编码,所以当我运行代码时,它成功打开登录gui,成功登录后,窗口被销毁,我希望它运行之后的代码,但出现此错误
Traceback (most recent call last):
File "D:\Users\SYSTEM H424\Desktop\Tanish\FUN\main.py", line 196, in <module>
entry_stock_entry = ttk.Combobox(master = main_window, values = ["reliance", "tata motors", "itc", "mahindra"], textvariable = vvariable)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\Users\SYSTEM H424\Desktop\Tanish\FUN\.venv\Lib\site-packages\ttkbootstrap\style.py", line 4941, in __init__
func(self, *args, **kwargs)
File "C:\Users\SYSTEM H424\AppData\Local\Programs\Python\Python312\Lib\tkinter\ttk.py", line 677, in __init__
Entry.__init__(self, master, "ttk::combobox", **kw)
File "D:\Users\SYSTEM H424\Desktop\Tanish\FUN\.venv\Lib\site-packages\ttkbootstrap\style.py", line 4960, in __init__
ttkstyle = Bootstyle.update_ttk_widget_style(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\Users\SYSTEM H424\Desktop\Tanish\FUN\.venv\Lib\site-packages\ttkbootstrap\style.py", line 5050, in update_ttk_widget_style
builder_method(builder, widget_color)
File "D:\Users\SYSTEM H424\Desktop\Tanish\FUN\.venv\Lib\site-packages\ttkbootstrap\style.py", line 1215, in create_combobox_style
arrowsize=self.scale_size(12),
^^^^^^^^^^^^^^^^^^^
File "D:\Users\SYSTEM H424\Desktop\Tanish\FUN\.venv\Lib\site-packages\ttkbootstrap\style.py", line 1116, in scale_size
winsys = self.style.master.tk.call("tk", "windowingsystem")
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_tkinter.TclError: can't invoke "tk" command: application has been destroyed
大约 3 个小时后,我现在很无助,我不明白为什么会触发它,因为就像创建了 GUI 一样。我还尝试调试它,添加了打印语句,甚至使用了 .protocall() 但没有任何帮助,甚至聊天 gpt 说你的代码一切正常,问题艾米在于库本身,它建议我重建整个应用程序。我是一个初学者,重建它听起来太无聊和忙碌,所以如果可能的话任何人都可以解决我的问题。我以前有登录和登录界面,可以互相交换,但我放弃了它,希望解决错误
可能是
ttkbootstrap
的设计/实现问题。
建议:
ttk.Toplevel()
而不是 ttk.Window()
作为登录窗口.wait_window()
而不是 .mainloop()
等待登录窗口关闭以下是一个简化的示例:
import ttkbootstrap as ttk
class Login:
def __init__(self):
self.authenticated_user = False
def login_gui(self):
login_window = ttk.Toplevel() # used ttk.Toplevel() instead of ttk.Window()
login_window.title('TSA Login')
login_window.geometry('400x250')
ttk.Button(login_window, text='Login', style='primary-outline', width=13,
command=lambda: self.authenticate_user(login_window)).place(x=160, y=160)
login_window.wait_window() # used wait_window() instead of mainloop()
def authenticate_user(self, window):
window.destroy()
self.authenticated_user = True
# create main window and hidden initially
main_window = ttk.Window(themename='darkly')
main_window.withdraw()
# show the login window
login = Login()
login.login_gui()
if login.authenticated_user:
main_window.title('Tanish Stock Exchange')
main_window.geometry('600x500')
def on_destroy():
print('Main window is being destroyed.')
main_window.destroy()
main_window.protocol('WM_DELETE_WINDOW', on_destroy)
stock_entry = ttk.Label(main_window, text='STOCK:', font=('arial', 15, 'bold'))
stock_entry.place(x=300, y=80)
vvariable = ttk.StringVar()
options = ['reliance', 'tata motors', 'itc', 'mahindra']
entry_stock_entry = ttk.Combobox(main_window, values=options, textvariable=vvariable)
entry_stock_entry.place(x=400, y=83)
main_window.deiconify() # resume the main window
main_window.mainloop()