我目前正在研究股票投资组合跟踪器,我对变量从一帧传递到另一帧的方式感到非常困惑。到目前为止,我基本上有两个框架,一个是树视图,第二个是 Userinputframe,一堆按钮和条目小部件。
我的代码应该使用这些条目小部件并将它们插入到我的树视图中。但是,现在它们进入了两个不同的框架,我无法设法从 Userinputframe 中获取()值以使用我的树视图,并且我收到错误讯息:'Frame' Object has no attribute 'Entry_ticker'。我在这里想念什么?
import tkinter
from tkinter import ttk
import datetime as dt
import yfinance as yf
import os
import csv
root_window = tkinter.Tk()
root_window.title('Python portfolio')
root_window.geometry('700x700')
# Frame functions
def call_first_frame():
second_frame.pack_forget()
first_frame.pack()
def call_second_frame():
first_frame.pack_forget()
second_frame.pack()
def call_third_frame():
second_frame.pack_forget()
def quit_program():
root_window.destroy()
# We create an csv flat file to store our values in
def create_database():
global header
header = ['Ticker', 'Volume', 'Purchased at', 'Current value']
with open('stocks.csv', 'w', encoding='UTF8', newline='') as f:
writer = csv.writer(f)
writer.writerow(header)
# we create a function to get the current share price of a ticker
def Shareprice(ticker):
ticker_yahoo = yf.Ticker(ticker)
data = ticker_yahoo.history()
return data.tail(1)['Close'].iloc[0]
# we use this to record a date of purchase
def stamp():
x = dt.datetime.now()
return x.strftime("%c")
# we fetch the price of the ticker entered
def CurrentPrice():
a=Shareprice(first_frame.Entry_ticker.get())
b=int(first_frame.Entry_volume.get())
return round(a*b,2)
# add an investment to the portfolio
def add_to_portfolio():
my_tree = ttk.Treeview(Treeviewframe, show='headings')
# Defining columns
my_tree['columns'] = ('Ticker', 'Volume', 'Purchased at', 'Current value')
# Column_formatting
my_tree.column('#0', anchor=tkinter.W, width=70, stretch=False)
my_tree.column('Ticker', anchor=tkinter.CENTER, width=50)
my_tree.column('Volume', anchor=tkinter.CENTER, width=50)
my_tree.column('Purchased at', anchor=tkinter.CENTER, width=175)
my_tree.column('Current value', anchor=tkinter.CENTER, width=150)
# Heading_formatting
my_tree.heading('#0', text='ID', anchor=tkinter.W)
my_tree.heading('Ticker', text='Ticker', anchor=tkinter.W)
my_tree.heading('Volume', text='Volume', anchor=tkinter.W)
my_tree.heading('Purchased at', text='Purchased at', anchor=tkinter.W)
my_tree.heading('Current value', text='Current value', anchor=tkinter.W)
global count
my_tree.insert(parent='', index='end', iid=count, text='',
values=(Userinputframe.Entry_ticker.get(), Userinputframe.Entry_volume.get(), stamp(), CurrentPrice()))
count = 1
# immediately after adding an investment in our treeview, we add our new investment to a our database
csvdata=[first_frame.Entry_ticker.get(), first_frame.Entry_volume.get(), stamp(), CurrentPrice()]
with open('stocks.csv', 'w', encoding='UTF8',newline='') as f:
writer = csv.writer(f)
writer.writerow(header)
with open('stocks.csv', 'a') as f:
writer = csv.writer(f)
writer.writerow(csvdata)
# We clear the entry widgets automatically when the button is pressed
first_frame.Entry_ticker.delete(0, tkinter.END)
first_frame.Entry_volume.delete(0, tkinter.END)
# remove one stock
def rmv_from_portfolio():
x = my_tree.selection()[0]
my_tree.delete(x)
# clear the portfolio (remove all stocks)
def rmv_all():
for record in my_tree.get_children():
my_tree.delete(record)
def start_tab_widgets():
# We initialize the Treeview to hold our portfolio
my_tree = ttk.Treeview(Treeviewframe, show='headings')
# Defining columns
my_tree['columns'] = ('Ticker', 'Volume', 'Purchased at', 'Current value')
# Column_formatting
my_tree.column('#0', anchor=tkinter.W, width=70, stretch=False)
my_tree.column('Ticker', anchor=tkinter.CENTER, width=50)
my_tree.column('Volume', anchor=tkinter.CENTER, width=50)
my_tree.column('Purchased at', anchor=tkinter.CENTER, width=175)
my_tree.column('Current value', anchor=tkinter.CENTER, width=150)
# Heading_formatting
my_tree.heading('#0', text='ID', anchor=tkinter.W)
my_tree.heading('Ticker', text='Ticker', anchor=tkinter.W)
my_tree.heading('Volume', text='Volume', anchor=tkinter.W)
my_tree.heading('Purchased at', text='Purchased at', anchor=tkinter.W)
my_tree.heading('Current value', text='Current value', anchor=tkinter.W)
# We find out if the user already has investments in his portfolio
path_name = 'stocks.csv'
if os.path.exists(path_name):
# then we read the data from the csv file, and make sure it appears in our treeview
old_data = []
else:
# then we create the database (CSV file)
create_database()
old_data = []
# We insert data in our portfolio
global count
count = 0
for record in old_data:
my_tree.insert(parent='', index='end', iid=count, text='', values=(record[0], record[1], record[2], record[3]))
count = 1
# widgets_user_input:Labels and entry
Lbl_ticker = tkinter.Label(Userinputframe, text='Ticker')
Lbl_ticker.grid(row=0, column=0, padx=10, pady=20, sticky='n')
Lbl_volume = tkinter.Label(Userinputframe, text='Volume')
Lbl_volume.grid(row=1, column=0, padx=10, pady=20, sticky='n')
Entry_ticker = tkinter.Entry(Userinputframe, text='Add ticker here...')
Entry_ticker.grid(row=0, column=1, pady=20, sticky='n', columnspan=2)
Entry_volume = tkinter.Entry(Userinputframe, text='Add nb of shares here...')
Entry_volume.grid(row=1, column=1, pady=20, sticky='n', columnspan=2)
# Buttons to add and remove records
Btn_add_record = tkinter.Button(Userinputframe, text='Add to portfolio', command=add_to_portfolio)
Btn_add_record.grid(row=2, column=1, pady=20, sticky='ns')
Btn_rmv_record = tkinter.Button(Userinputframe, text='Remove one selected stock', command=rmv_from_portfolio)
Btn_rmv_record.grid(row=3,column=1, pady=20, sticky='n')
Btn_rmv_all = tkinter.Button(Userinputframe, text='Clear my portfolio', command=rmv_all)
Btn_rmv_all.grid(row=4, column=1, pady=20, sticky='n')
# we pack our Tree view onto our frame
my_tree.pack(in_=Treeviewframe, pady=20, padx=0, fill='y')
# we place those two frames one after the other
Treeviewframe.pack(in_=first_frame, pady=20)
Treeviewframe['borderwidth'] = 0
Userinputframe.pack(in_=first_frame, pady=20)
Userinputframe['borderwidth'] = 0
# Buttons to leave the program
# We declare our frames
first_frame = tkinter.ttk.Frame(root_window)
first_frame.pack()
# we define two sub-frames to work into
Treeviewframe = tkinter.ttk.Frame(first_frame)
Userinputframe = tkinter.ttk.Frame(first_frame)
second_frame = tkinter.Frame(root_window)
second_frame.pack()
third_frame = tkinter.Frame(root_window)
third_frame.pack()
# We hide all frames in reverse order, but leave the first frame visible
start_tab_widgets()
'''
portfolio_widgets()
reco_widgets()
'''
# Hide all frames in reverse order, but we leave the first frame visible
third_frame.pack_forget()
second_frame.pack_forget()
# we add this program to the main loop
root_window.mainloop()
uj5u.com热心网友回复:
查看代码,错误:Frame' Object has no attribute 'Entry_ticker'
是预期的。
Entry_ticker
是一个区域变量,而不是Userinputframe
.
这里有几个选项:
选项 1:将您的条目定义为全域变量
entry_ticker = None
....
...
...
def start_tab_widgets():
...
...
global entry_ticker
entry_ticker = tkinter.Entry(Userinputframe, text='Add ticker here...')
entry_ticker.grid(row=0, column=1, pady=20, sticky='n', columnspan=2)
def add_to_portfolio():
...
...
#access entry_ticker
global entry_ticker
value = entry_ticker.get()
选项 2:为您的框架创建一个新类并定义一个类级别变量
class UserInputFrame:
def __init__(self, parent):
self.frame = tkinter.ttk.Frame(parent)
self.entry_ticker = tkinter.Entry(self.frame, text='Add ticker here...')
self.entry_ticker.grid(row=0, column=1, pady=20, sticky='n', columnspan=2)
def start_tab_widgets():
....
....
....
# Create class instance
user_input_frame = UserInputFrame(root_window)
# Access the entry_ticker value
user_input_frame.entry_ticker.get()
选项 3:使用 tkinter.StringVar()
现在,访问该值的最合适的选项是<type>Var()
在您的情况下使用 tkinter可以使用 StringVar()。因此,当您创建条目时
# create the stringvar
entry_ticker_var = tkinter.StringVar()
# Use the var while createing entry (textvariable=entry_ticker_var)
entry_ticker = tkinter.Entry(self.frame, text='Add ticker here...', textvariable=entry_ticker_var)
....
....
现在,在使用它时只需呼叫entry_ticker.get()
或者如果您想更新条目中的文本,您可以entry_ticker.set("New Value")
您还可以将跟踪事件系结到此变量entry_ticker.trace_add('write', on_change)
。on_change
每当您的该变量的值发生更改时(即每当用户将输入写入文本框时),都会呼叫此处的函式
选项 4:选项 2 和 3 一起(推荐)
类用户输入帧:
def __init__(self, parent):
# create the variable
self.entry_ticker_var = tkinter.StringVar()
# create frame
frame = tkinter.ttk.Frame(parent)
# create text box
entry_ticker = tkinter.Entry(self.frame, text='Add ticker here...', textvariable=self.entry_ticker_var)
entry_ticker.grid(row=0, column=1, pady=20, sticky='n', columnspan=2)
def start_tab_widgets():
....
....
....
# Create class instance
user_input_frame = UserInputFrame(root_window)
# Access the entry_ticker value
user_input_frame.entry_ticker_var.get()
参考:
Python Tkinter
python Tkinter 模块
在旁注中,如果您想访问框架的子小部件,您可能需要使用 winfo_children()
for child in Userinputframe.winfo_children():
widget_type = child.winfo_class()
if widget_type == 'Entry':
# do stuff
0 评论