拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 使用来自另一个框架的条目小部件插入另一个框架(Treeview小部件)

使用来自另一个框架的条目小部件插入另一个框架(Treeview小部件)

白鹭 - 2022-02-22 1974 0 0

我目前正在研究股票投资组合跟踪器,我对变量从一帧传递到另一帧的方式感到非常困惑。到目前为止,我基本上有两个框架,一个是树视图,第二个是 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 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *