我是python编程的新手,我正在尝试为时间序列数据创建两个可滚动框架,但是当我添加动态框架时,它们都没有激活。每个框架包含3个部分,这些部分在第1列中显示变量,在第2列中显示图表,在第3行Snapshot of the GUI中显示唯一日期。我收到以下错误:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\ranji\Anaconda3\lib\tkinter\__init__.py", line 1702, in __call__
return self.func(*args)
File "C:\Users\ranji\Anaconda3\lib\tkinter\__init__.py", line 3069, in set
self.tk.call(self._w, 'set', first, last)
_tkinter.TclError: invalid command name ".!scrollbar"
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\ranji\Anaconda3\lib\tkinter\__init__.py", line 1702, in __call__
return self.func(*args)
File "C:\Users\ranji\Anaconda3\lib\tkinter\__init__.py", line 3069, in set
self.tk.call(self._w, 'set', first, last)
_tkinter.TclError: invalid command name ".!scrollbar2"
任何人都可以帮助我找到错误的根源吗?
下面是我的代码:
import os
import tkinter as tk
#from tkinter import ttk
from tkinter import filedialog as fd
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
def on_configure(event):
# update scrollregion after starting 'mainloop'
canvas1.configure(scrollregion=canvas1.bbox('all'))
canvas2.configure(scrollregion=canvas2.bbox('all'))
root = tk.Tk()
root.geometry('{}x{}'.format(800, 600))
# layout all of the main containers
root.grid_rowconfigure(1, weight=1)
root.grid_columnconfigure(0, weight=1)
#Global variables
category = tk.StringVar()
global rownum
rownum =0
mindatetime = pd.to_datetime('1900-01-01 00:00:00')
maxdatetime = pd.to_datetime('1900-01-01 00:00:00')
def enterCategory():
global cat
cat = category.get()
global catmainframe
global rownum
global add_file
catmainframe = tk.Frame(canvas1, borderwidth=2, relief="solid")
catmainframe.grid(row=rownum,column=0,sticky='nsew', padx=3, pady=3)
catmainframe.grid_rowconfigure(0, weight=1)
catmainframe.grid_columnconfigure(0, weight=1)
catframe = tk.Frame(catmainframe, borderwidth=2, relief="solid")
catframe.grid(row=0,column=0, sticky='nsew', padx=1, pady=1)
catlabel = tk.Label(catframe, text=cat)
catlabel.grid(row=0, column=0, sticky='nsew')
add_file = tk.Button(catframe,text="Add File",command=openFile)
add_file.grid(row=0, column=1, sticky='nsew')
global catchildframe
catchildframe = tk.Frame(catmainframe, borderwidth=2, relief="solid")
catchildframe.grid(row=1,column=0,sticky='nsew', padx=1, pady=1)
catchildframe.grid_rowconfigure(1, weight=1)
catchildframe.grid_columnconfigure(1, weight=1)
global box1, box2, box3
box1 = tk.Frame(catchildframe, borderwidth=2, relief="solid")
box2 = tk.Frame(catchildframe, borderwidth=2, relief="solid")
box3 = tk.Frame(catchildframe, borderwidth=2, relief="solid")
box1.grid(row=1, column=0, sticky='nsew', padx=10, pady=10)
box2.grid(row=1, column=1, sticky='nsew', padx=10, pady=10)
box3.grid(row=1, column=2, sticky='nsew', padx=10, pady=10)
box1.propagate(1)
box2.propagate(1)
box3.propagate(1)
rownum = rownum +1
def openFile():
parentname = catmainframe.winfo_parent()
parent = catmainframe._nametowidget(parentname)
#childname = catchildframe.winfo_parent()
#child = catchildframe._nametowidget(childname)
child = add_file.master
print("Catmainframe parent:"+parentname)
#print("Catchildframe parent:"+child)
global fname
global mindatetime
global maxdatetime
file_path=fd.askopenfilename()
#print(file_path)
file_name = os.path.basename(file_path)
print(file_name)
file_list = []
file_list.append(file_name)
df = pd.read_csv(file_path)
names = list(df.columns[0:])
indexcol = names[0]
#print(indexcol)
df = df.rename(columns = {indexcol:'datetime'})
names = list(df.columns[1:])
#print(names)
df.datetime = pd.to_datetime(df.datetime)
df.set_index('datetime',inplace=True)
if mindatetime == pd.to_datetime('1900-01-01 00:00:00'):
mindatetime = df.index.min()
elif mindatetime > df.index.min():
mindatetime = df.index.min()
if maxdatetime == pd.to_datetime('1900-01-01 00:00:00'):
maxdatetime = df.index.max()
elif maxdatetime < df.index.max():
maxdatetime = df.index.max()
print(mindatetime)
print(maxdatetime)
global unique_dates
unique_dates = []
unique_dates = df.index.map(pd.Timestamp.date).unique()
for x in range(len(names)):
if(len(names)==1):
l = tk.Checkbutton(box1, text=names[x], variable=names[x],state='disabled')
l.select()
l.pack(anchor = 'w')
else:
l = tk.Checkbutton(box1, text=names[x], variable=names[x])
l.select()
l.pack(anchor = 'w')
figure = plt.Figure(figsize=(5,4), dpi=100)
ax2 = figure.add_subplot(111)
line = FigureCanvasTkAgg(figure, box2)
line.get_tk_widget().grid(row=1,column=1,sticky='nsew')
df.plot(kind='line', legend=False, ax=ax2, fontsize=10)
ax2.set_title(cat)
ax2.set_xlim(mindatetime,maxdatetime)
for x in range(len(unique_dates)):
d = tk.Checkbutton(box3, text=unique_dates[x], variable=unique_dates[x])
d.select()
d.pack(anchor = 'w')
#Top frame
top_frame = tk.Frame(root)
top_frame.grid(row=0, column=0, sticky='nsew')
category_name = tk.Label(top_frame, text='Category:')
category_name.grid(row=0, column=0, sticky='nsew')
entry_category = tk.Entry(top_frame, background="pink",textvariable = category)
entry_category.grid(row=0, column=1, sticky='nsew')
entry_category.focus()
ok_button = tk.Button(top_frame, text="OK", command=enterCategory)
ok_button.grid(row=0, column=2, sticky='nsew')
xscrollbar = tk.Scrollbar(root, orient='horizontal')
xscrollbar.grid(row=3, column=0, sticky='ew')
yscrollbar = tk.Scrollbar(root)
yscrollbar.grid(row=1, column=1, sticky='ns')
canvas1 = tk.Canvas(root, bd=0,#scrollregion=(0, 0, 1000, 1000),
yscrollcommand=yscrollbar.set)
canvas1.grid(row=1, column=0, sticky='nsew')
# create the center widgets
canvas1.grid_rowconfigure(1, weight=1)
canvas1.grid_columnconfigure(0, weight=1)
canvas2 = tk.Canvas(root, bd=0,#scrollregion=(0, 0, 1000, 1000),
xscrollcommand=xscrollbar.set)
canvas2.grid(row=2, column=0, sticky='nsew')
xscrollbar.config(command=canvas2.xview)
yscrollbar.config(command=canvas1.yview)
canvas1.config(scrollregion=canvas1.bbox("all"))
canvas2.config(scrollregion=canvas2.bbox("all"))
root.mainloop()
答案 0 :(得分:0)
您已经知道这一点,但我将所有内容放在一起
要将小部件添加到Canvas
,必须使用
canvas.create_window(position, window=widget)
而不是grid()
。
如果您不使用create_window()
,则画布为空,滚动条无滚动内容。
catmainframe = tk.Frame(canvas1, borderwidth=2, relief="solid")
canvas1.create_window((0,0), window=catmainframe, anchor='nw') #, width=750)
您还必须添加
root.bind('<Configure>', on_configure)
运行功能,该功能将更新滚动条的信息以滚动多大的区域。
您可以直接在root.mainloop()
我曾经测试过的代码-进行了一些其他清理:所有函数都在代码开头,所有global
在函数开头。
import os
import tkinter as tk
from tkinter import filedialog as fd
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
# --- functions ---
# all functions at the beginning to make it more readable
def on_configure(event):
# update scrollregion after starting 'mainloop'
canvas1.configure(scrollregion=canvas1.bbox('all'))
canvas2.configure(scrollregion=canvas2.bbox('all'))
def enterCategory():
# all `global` at the beginning to make it more readable
global cat
global catmainframe
global rownum
global add_file
global catchildframe
global box1, box2, box3
cat = category.get()
catmainframe = tk.Frame(canvas1, borderwidth=2, relief="solid")
canvas1.create_window((0,0), window=catmainframe, anchor='nw')#, width=750)
catmainframe.grid_rowconfigure(0, weight=1)
catmainframe.grid_columnconfigure(0, weight=1)
catframe = tk.Frame(catmainframe, borderwidth=2, relief="solid")
catframe.grid(row=0,column=0, sticky='nsew', padx=1, pady=1)
catlabel = tk.Label(catframe, text=cat)
catlabel.grid(row=0, column=0, sticky='nsew')
add_file = tk.Button(catframe, text="Add File", command=openFile)
add_file.grid(row=0, column=1, sticky='nsew')
catchildframe = tk.Frame(catmainframe, borderwidth=2, relief="solid")
catchildframe.grid(row=1,column=0,sticky='nsew', padx=1, pady=1)
catchildframe.grid_rowconfigure(1, weight=1)
catchildframe.grid_columnconfigure(1, weight=1)
box1 = tk.Frame(catchildframe, borderwidth=2, relief="solid")
box2 = tk.Frame(catchildframe, borderwidth=2, relief="solid")
box3 = tk.Frame(catchildframe, borderwidth=2, relief="solid")
box1.grid(row=1, column=0, sticky='nsew', padx=10, pady=10)
box2.grid(row=1, column=1, sticky='nsew', padx=10, pady=10)
box3.grid(row=1, column=2, sticky='nsew', padx=10, pady=10)
box1.propagate(1)
box2.propagate(1)
box3.propagate(1)
rownum += 1
def openFile():
# all `global` at the beginning to make it more readable
global fname
global mindatetime
global maxdatetime
global unique_dates
parentname = catmainframe.winfo_parent()
parent = catmainframe._nametowidget(parentname)
#childname = catchildframe.winfo_parent()
#child = catchildframe._nametowidget(childname)
child = add_file.master
print("Catmainframe parent:", parentname)
#print("Catchildframe parent:"+child)
file_path = fd.askopenfilename()
#print(file_path)
file_name = os.path.basename(file_path)
print(file_name)
file_list = []
file_list.append(file_name)
df = pd.read_csv(file_path)
names = list(df.columns[0:])
indexcol = names[0]
#print(indexcol)
df = df.rename(columns = {indexcol:'datetime'})
names = list(df.columns[1:])
#print(names)
df.datetime = pd.to_datetime(df.datetime)
df.set_index('datetime', inplace=True)
if mindatetime == pd.to_datetime('1900-01-01 00:00:00'):
mindatetime = df.index.min()
elif mindatetime > df.index.min():
mindatetime = df.index.min()
if maxdatetime == pd.to_datetime('1900-01-01 00:00:00'):
maxdatetime = df.index.max()
elif maxdatetime < df.index.max():
maxdatetime = df.index.max()
print(mindatetime)
print(maxdatetime)
unique_dates = []
unique_dates = df.index.map(pd.Timestamp.date).unique()
for x in range(len(names)):
l = tk.Checkbutton(box1, text=names[x], variable=names[x])
if len(names) == 1:
l['state'] = 'disabled'
l.select()
l.pack(anchor='w')
figure = plt.Figure(figsize=(5,4), dpi=100)
ax2 = figure.add_subplot(111)
line = FigureCanvasTkAgg(figure, box2)
line.get_tk_widget().grid(row=1, column=1, sticky='nsew')
df.plot(kind='line', legend=False, ax=ax2, fontsize=10)
ax2.set_title(cat)
ax2.set_xlim(mindatetime,maxdatetime)
for x in range(len(unique_dates)):
d = tk.Checkbutton(box3, text=unique_dates[x], variable=unique_dates[x])
d.select()
d.pack(anchor='w')
# --- main ---
# global is used only inside function to inform function
# that you want to use external/global variable when you assign value
# and then it doesn't create local variable
#global rownum # not needed # all variables created outside functionsa are glboal
root = tk.Tk()
root.geometry('{}x{}'.format(800, 600))
# layout all of the main containers
root.grid_rowconfigure(1, weight=1)
root.grid_columnconfigure(0, weight=1)
#Global variables
category = tk.StringVar()
rownum = 0
mindatetime = pd.to_datetime('1900-01-01 00:00:00')
maxdatetime = pd.to_datetime('1900-01-01 00:00:00')
#Top frame
top_frame = tk.Frame(root)
top_frame.grid(row=0, column=0, sticky='nsew')
category_name = tk.Label(top_frame, text='Category:')
category_name.grid(row=0, column=0, sticky='nsew')
entry_category = tk.Entry(top_frame, background="pink",textvariable = category)
entry_category.grid(row=0, column=1, sticky='nsew')
entry_category.focus()
ok_button = tk.Button(top_frame, text="OK", command=enterCategory)
ok_button.grid(row=0, column=2, sticky='nsew')
xscrollbar = tk.Scrollbar(root, orient='horizontal')
xscrollbar.grid(row=3, column=0, sticky='ew')
yscrollbar = tk.Scrollbar(root)
yscrollbar.grid(row=1, column=1, sticky='ns')
canvas1 = tk.Canvas(root, bd=0,#scrollregion=(0, 0, 1000, 1000),
yscrollcommand=yscrollbar.set)
canvas1.grid(row=1, column=0, sticky='nsew')
# create the center widgets
canvas1.grid_rowconfigure(1, weight=1)
canvas1.grid_columnconfigure(0, weight=1)
canvas2 = tk.Canvas(root, bd=0,#scrollregion=(0, 0, 1000, 1000),
xscrollcommand=xscrollbar.set)
canvas2.grid(row=2, column=0, sticky='nsew')
xscrollbar.config(command=canvas2.xview)
yscrollbar.config(command=canvas1.yview)
root.bind('<Configure>', on_configure)
root.mainloop()