Python 3:_tkinter.TclError:无效的命令名称“。!scrollbar”

时间:2019-09-13 01:43:55

标签: python tkinter time-series frames scrollable

我是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()

1 个答案:

答案 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()