Python 为什么小部件在tkinter画布中堆叠在一起?

Python 为什么小部件在tkinter画布中堆叠在一起?,python,tkinter,widget,tkinter-canvas,Python,Tkinter,Widget,Tkinter Canvas,我一直在使用tkinter在python中创建一个程序,我有一个下载选项卡,它需要一个滚动条。在一些谷歌搜索之后,我发现让一个完整的应用程序可以滚动并不容易,因为只有几个小部件本机支持滚动条小部件。我搜索了它并找到了一种方法,然而,当我试图自己实现它时,我遇到了一个错误。当我用这个方法使用网格时,小部件彼此堆叠在一起,而不是在单独的行上。我试着像教程一样用for循环做同样的事情,问题解决了,但我不希望我的程序使用for循环。以下是不带for循环的代码: from tkinter import *

我一直在使用tkinter在python中创建一个程序,我有一个下载选项卡,它需要一个滚动条。在一些谷歌搜索之后,我发现让一个完整的应用程序可以滚动并不容易,因为只有几个小部件本机支持滚动条小部件。我搜索了它并找到了一种方法,然而,当我试图自己实现它时,我遇到了一个错误。当我用这个方法使用网格时,小部件彼此堆叠在一起,而不是在单独的行上。我试着像教程一样用for循环做同样的事情,问题解决了,但我不希望我的程序使用for循环。以下是不带for循环的代码:

from tkinter import *
from tkinter import ttk

available_row = 0

root = Tk()
root.title("A Scrollbar")
root.geometry("580x308")
# Create a download frame
download_fr = Frame(root, width=580, height=308)
big_lbl = Label(download_fr, text="Just a BIG label. ", font=("Helvetica", "30", "bold"))
prg_br = ttk.Progressbar(download_fr, orient=HORIZONTAL, length=300, mode='indeterminate')



def pack_bars():
    global available_row
    big_lbl.pack_forget()
    prg_br.pack_forget()
    # Pack the Scrollbar
    my_scrollbar.pack(side=RIGHT, fill=Y)
    # Configure the canvas
    cnava.configure(yscrollcommand=my_scrollbar.set)
    cnava.bind("<Configure>", lambda e: cnava.configure(scrollregion=cnava.bbox("all")))
    # Create another frame inside the canvas
    second_frame = Frame(cnava)
    # Add that new frame to a window in the canvas
    cnava.create_window((0, 0), window=second_frame, anchor="nw")
    ttk.Button(second_frame, text=f"This is the {available_row}th button").grid(row=available_row, column=0)
    available_row += 1
    print(f"Next available row: {available_row}")


btn = Button(download_fr, text="Pack progress bars. ", command=pack_bars)
# Create a canvas
cnava = Canvas(download_fr, bg="red")
# Create a Scrollbar
my_scrollbar = ttk.Scrollbar(download_fr, orient=VERTICAL, command=cnava.yview)
big_lbl.pack(pady=(85, 5))
prg_br.pack()
prg_br.start(5)
cnava.pack(side=LEFT, fill=BOTH, expand=1)
btn.pack()
download_fr.pack(fill=BOTH, expand=1)
root.mainloop()
from tkinter import *
from tkinter import ttk


root = Tk()
root.title("A Scrollbar")
root.geometry("580x308")
# Create a download frame
download_fr = Frame(root, width=580, height=308)
big_lbl = Label(download_fr, text="Just a BIG label. ", font=("Helvetica", "30", "bold"))
prg_br = ttk.Progressbar(download_fr, orient=HORIZONTAL, length=300, mode='indeterminate')


def pack_bars():
    big_lbl.pack_forget()
    prg_br.pack_forget()
    # Pack the Scrollbar
    my_scrollbar.pack(side=RIGHT, fill=Y)
    # Configure the canvas
    cnava.configure(yscrollcommand=my_scrollbar.set)
    cnava.bind("<Configure>", lambda e: cnava.configure(scrollregion=cnava.bbox("all")))
    # Create another frame inside the canvas
    second_frame = Frame(cnava)
    # Add that new frame to a window in the canvas
    cnava.create_window((0, 0), window=second_frame, anchor="nw")
    # Creating a loop to grid 100 buttons
    for i in range(100):
        ttk.Button(second_frame, text=f"This is the {i}th button").grid(row=i, column=0)


btn = Button(download_fr, text="Pack progress bars. ", command=pack_bars)
# Create a canvas
cnava = Canvas(download_fr, bg="red")
# Create a Scrollbar
my_scrollbar = ttk.Scrollbar(download_fr, orient=VERTICAL, command=cnava.yview)
big_lbl.pack(pady=(85, 5))
prg_br.pack()
prg_br.start(5)
cnava.pack(side=LEFT, fill=BOTH, expand=1)
btn.pack()
download_fr.pack(fill=BOTH, expand=1)
root.mainloop()
从tkinter导入*
从tkinter导入ttk
可用行=0
root=Tk()
root.title(“滚动条”)
根几何(“580x308”)
#创建下载框架
下载\u fr=Frame(根,宽度=580,高度=308)
大标签(下载,text=“只是一个大标签”,font=(“Helvetica”,“30”,“bold”))
prg\u br=ttk.Progressbar(下载,方向=水平,长度=300,模式=不确定)
def包装条():
全球可用行
大包
prg_br.打包忘记()
#打包滚动条
my_scrollbar.pack(侧=右,填充=Y)
#配置画布
配置(yscrollcommand=my_scrollbar.set)
cnava.bind(“,lambda e:cnava.configure(scrollregion=cnava.bbox(“全部”))
#在画布内创建另一个框架
第二帧=帧(cnava)
#将新框架添加到画布中的窗口
cnava.create_window((0,0),window=second_frame,anchor=“nw”)
ttk.Button(第二帧,text=f“这是第{available\u row}个按钮”).grid(row=available\u row,column=0)
可用行+=1
打印(f“下一个可用行:{available_row}”)
btn=按钮(下载进度条,text=“打包进度条”,命令=打包进度条)
#创建画布
cnava=Canvas(下载
#创建一个滚动条
my_scrollbar=ttk.scrollbar(下载,方向=VERTICAL,命令=cnava.yview)
大包装(帕迪=(85,5))
prg_br.pack()
启动程序(5)
cnava.pack(侧面=左侧,填充=两侧,展开=1)
btn.pack()
下载包装(填充=两者,扩展=1)
root.mainloop()
下面是与for循环相同的代码:

from tkinter import *
from tkinter import ttk

available_row = 0

root = Tk()
root.title("A Scrollbar")
root.geometry("580x308")
# Create a download frame
download_fr = Frame(root, width=580, height=308)
big_lbl = Label(download_fr, text="Just a BIG label. ", font=("Helvetica", "30", "bold"))
prg_br = ttk.Progressbar(download_fr, orient=HORIZONTAL, length=300, mode='indeterminate')



def pack_bars():
    global available_row
    big_lbl.pack_forget()
    prg_br.pack_forget()
    # Pack the Scrollbar
    my_scrollbar.pack(side=RIGHT, fill=Y)
    # Configure the canvas
    cnava.configure(yscrollcommand=my_scrollbar.set)
    cnava.bind("<Configure>", lambda e: cnava.configure(scrollregion=cnava.bbox("all")))
    # Create another frame inside the canvas
    second_frame = Frame(cnava)
    # Add that new frame to a window in the canvas
    cnava.create_window((0, 0), window=second_frame, anchor="nw")
    ttk.Button(second_frame, text=f"This is the {available_row}th button").grid(row=available_row, column=0)
    available_row += 1
    print(f"Next available row: {available_row}")


btn = Button(download_fr, text="Pack progress bars. ", command=pack_bars)
# Create a canvas
cnava = Canvas(download_fr, bg="red")
# Create a Scrollbar
my_scrollbar = ttk.Scrollbar(download_fr, orient=VERTICAL, command=cnava.yview)
big_lbl.pack(pady=(85, 5))
prg_br.pack()
prg_br.start(5)
cnava.pack(side=LEFT, fill=BOTH, expand=1)
btn.pack()
download_fr.pack(fill=BOTH, expand=1)
root.mainloop()
from tkinter import *
from tkinter import ttk


root = Tk()
root.title("A Scrollbar")
root.geometry("580x308")
# Create a download frame
download_fr = Frame(root, width=580, height=308)
big_lbl = Label(download_fr, text="Just a BIG label. ", font=("Helvetica", "30", "bold"))
prg_br = ttk.Progressbar(download_fr, orient=HORIZONTAL, length=300, mode='indeterminate')


def pack_bars():
    big_lbl.pack_forget()
    prg_br.pack_forget()
    # Pack the Scrollbar
    my_scrollbar.pack(side=RIGHT, fill=Y)
    # Configure the canvas
    cnava.configure(yscrollcommand=my_scrollbar.set)
    cnava.bind("<Configure>", lambda e: cnava.configure(scrollregion=cnava.bbox("all")))
    # Create another frame inside the canvas
    second_frame = Frame(cnava)
    # Add that new frame to a window in the canvas
    cnava.create_window((0, 0), window=second_frame, anchor="nw")
    # Creating a loop to grid 100 buttons
    for i in range(100):
        ttk.Button(second_frame, text=f"This is the {i}th button").grid(row=i, column=0)


btn = Button(download_fr, text="Pack progress bars. ", command=pack_bars)
# Create a canvas
cnava = Canvas(download_fr, bg="red")
# Create a Scrollbar
my_scrollbar = ttk.Scrollbar(download_fr, orient=VERTICAL, command=cnava.yview)
big_lbl.pack(pady=(85, 5))
prg_br.pack()
prg_br.start(5)
cnava.pack(side=LEFT, fill=BOTH, expand=1)
btn.pack()
download_fr.pack(fill=BOTH, expand=1)
root.mainloop()
从tkinter导入*
从tkinter导入ttk
root=Tk()
root.title(“滚动条”)
根几何(“580x308”)
#创建下载框架
下载\u fr=Frame(根,宽度=580,高度=308)
大标签(下载,text=“只是一个大标签”,font=(“Helvetica”,“30”,“bold”))
prg\u br=ttk.Progressbar(下载,方向=水平,长度=300,模式=不确定)
def包装条():
大包
prg_br.打包忘记()
#打包滚动条
my_scrollbar.pack(侧=右,填充=Y)
#配置画布
配置(yscrollcommand=my_scrollbar.set)
cnava.bind(“,lambda e:cnava.configure(scrollregion=cnava.bbox(“全部”))
#在画布内创建另一个框架
第二帧=帧(cnava)
#将新框架添加到画布中的窗口
cnava.create_window((0,0),window=second_frame,anchor=“nw”)
#创建到栅格100个按钮的循环
对于范围(100)内的i:
ttk.Button(第二帧,text=f“这是第{i}个按钮”).grid(行=i,列=0)
btn=按钮(下载进度条,text=“打包进度条”,命令=打包进度条)
#创建画布
cnava=Canvas(下载
#创建一个滚动条
my_scrollbar=ttk.scrollbar(下载,方向=VERTICAL,命令=cnava.yview)
大包装(帕迪=(85,5))
prg_br.pack()
启动程序(5)
cnava.pack(侧面=左侧,填充=两侧,展开=1)
btn.pack()
下载包装(填充=两者,扩展=1)
root.mainloop()

看起来,在第一个程序中,画布没有调整大小,因为红色区域没有改变,因此按钮彼此重叠。如何解决此问题?

您可以创建一个新的
第二帧
,并在执行
打包条()
时将其放置在画布中的相同位置。您应该在函数外部创建一次
第二个\u帧

您还应该在
第二帧上绑定
,而不是
cnava

以下是基于您的修改后的代码:

从tkinter导入*
从tkinter导入ttk
可用行=0
root=Tk()
root.title(“滚动条”)
根几何(“580x308”)
#创建下载框架
下载\u fr=Frame(根,宽度=580,高度=308)
大标签(下载,text=“只是一个大标签”,font=(“Helvetica”,“30”,“bold”))
prg\u br=ttk.Progressbar(下载,方向=水平,长度=300,模式=不确定)
def包装条():
全球可用行
大包
prg_br.打包忘记()
#打包滚动条
my_scrollbar.pack(侧=右,填充=Y)
#将新按钮添加到第二个_帧
ttk.Button(第二帧,text=f“这是第{available\u row}个按钮”).grid(row=available\u row,column=0)
可用行+=1
打印(f“下一个可用行:{available_row}”)
btn=按钮(下载进度条,text=“打包进度条”,命令=打包进度条)
#创建画布
cnava=Canvas(下载
#创建一个滚动条
my_scrollbar=ttk.scrollbar(下载,方向=VERTICAL,命令=cnava.yview)
配置(yscrollcommand=my_scrollbar.set)
大包装(帕迪=(85,5))
prg_br.pack()
启动程序(5)
cnava.pack(侧面=左侧,填充=两侧,展开=1)
btn.pack()
下载包装(填充=两者,扩展=1)
#在画布内创建另一个框架
第二帧=帧(cnava)
#将新框架添加到画布中的窗口
cnava.create_window(0,0,window=second_frame,anchor='nw')
#每当第二个_帧的大小更改时,更新画布滚动区域
第二帧绑定(“”,lambda e:cnava.configure(scrollregion=cnava.bbox('all'))
root.mainloop()

谢谢您的解释!你是对的,我应该在函数外定义框架。为什么我自己没想到呢!你真了不起