我正在调试可滚动框架,以容纳一个框架,该框架可以增大到更大的尺寸,然后减小(包含的小部件被销毁,并且放回了较小的数字)。框架是:frame.grid(column = 0,row = 0,sticky ='nw')。但是,较小的框架有点放在画布的中间。如果运行此示例,则最初将获得9个复选按钮和条目的列表。如果按显示更多按钮,您将看到所有30个按钮/条目,然后按显示较少的按钮,您将看到原始框架,但它不在画布的西北角。
import tkinter as tk
from tkinter import ttk
import os
import inspect
import functools
import sys
class ScrollableFrame:
# https://blog.tecladocode.com/tkinter-scrollable-frame
def __init__(self,container):
self.container = container
self.top_frame = tk.Frame(container,height=2)
self.top_frame.configure(bg='gray15')
# create a frame to hold the Canvas andscrollbars
self.canvas = tk.Canvas(container,borderwidth=5)
self.canvas.configure(bg = 'orange')
#self.canvas.pack_propagate(False)
self.content_frame = tk.Frame(self.canvas, bg = 'yellow')
#self.content_frame.grid_propagate(True)
# create a vertical scrollbar linked to the canvas
self.scrollbar = ttk.Scrollbar(self.canvas, orient="vertical", command=self.canvas.yview)
self.canvas.configure(yscrollcommand=self.scrollbar.set) # again scrollbar.set is a provided function
self.scrollbar.config(command=self.canvas.yview)
self.xscrollbar = ttk.Scrollbar(self.canvas, orient = 'horizontal', command=self.canvas.xview)
self.canvas.configure(xscrollcommand=self.xscrollbar.set)
self.xscrollbar.config(command=self.canvas.xview)
# before we are done we need to put buttons into ScrollableFame, row 0
# and populate the content_frame with widgets
# after this has been done, the bounding box must be created
container.bind(
"<Configure>",
lambda e: self.canvas.configure(
scrollregion=self.canvas.bbox("all")
)
)
def finish(self):
self.container.config(bg = 'lightgreen')
self.top_frame.pack(side=tk.TOP,fill=tk.BOTH,expand=False)
#self.content_frame.pack(side=tk.TOP,fill = tk.BOTH,expand=False)
self.content_frame.grid(column=0,row=0,sticky='nw',ipadx = 5,ipady=5)
self.canvas.create_window((0,0), window=self.content_frame)
self.canvas.pack(side=tk.TOP,fill=tk.BOTH,expand=True,ipady=10)
self.canvas.configure(scrollregion=self.canvas.bbox('all'))
self.canvas.pack_propagate(False)
self.scrollbar.pack(fill='both',side='right',expand='false')
self.xscrollbar.pack(fill='both',side='bottom',expand='false')
#self.container.grid(column=0,row=0,sticky='nsew')
#self.container.rowconfigure(0,weight=1)
#self.container.columnconfigure(0,weight=1)
self.canvas.update_idletasks()
self.canvas.yview_moveto(0)
self.canvas.xview_moveto(0)
class DisplayKeys(tk.Frame):
def __init__(self,parent,*args,**kwargs) :
tk.Frame.__init__(self,parent,*args,**kwargs)
self.keys_ = [f'display{i}' for i in range(30)]
self._showless = False
self._checkbuttons_initialized = None
self.scrollable_frame = ScrollableFrame(parent)
self._label = tk.Label(self.scrollable_frame.top_frame,
text = "Key List",font = LARGE_FONT)
self._label.grid(column=0,row=0)
self._sequence = [1,2,3,29,5,7,21,15,6]
self._showbutton = tk.Button(self.scrollable_frame.top_frame,
text='Show More',
command=lambda:
self._showbutton_action())
self._showbutton.grid(column=2,row=0,padx=10,sticky=tk.N)
self._update_checkbuttons(
self.scrollable_frame.content_frame,self._sequence )
#self.scrollable_frame.finish()
def _update_checkbuttons(self,frame,seq):
#print(*seq)
if self._checkbuttons_initialized != None :
for widget in self.scrollable_frame.content_frame.winfo_children() :
widget.destroy()
self._checkbuttons_initialized = True
self.checkVars = []
self.txtVars = []
searchVar = "Search"
self._checkbuttons = []
for i,place in enumerate(seq) :
bv = tk.BooleanVar()
tvar = tk.StringVar()
dn = self.keys_[place]
ck = tk.Checkbutton(frame,text=dn,variable=bv)
ck.grid(column=0,row=i,sticky='nw')
self._checkbuttons.append(ck)
self.checkVars.append(bv)
txt = tk.Entry(frame,width = 30, textvariable = tvar)
txt.bind('<Return>',self._cmgo)
txt.grid(column = 1,row = i,sticky="nw")
#txt.rowconfigure(0,minsize=400,weight = 1)
#txt.columnconfigure(0,weight=1)
self.txtVars.append(tvar)
self.scrollable_frame.finish()
#self.scrollable_frame.canvas.pack()
#tk.Label(frame,height=1,bg = 'skyblue').grid(column=0,row=len(seq)+1)
#self.scrollable_frame.canvas.configure(scrollregion=self.scrollable_frame.canvas.bbox("all") )
def _cmgo(self):
pass
def _showbutton_action(self):
if not self._showless :
self._sequence = range(len(self.keys_))
self._showbutton.configure( text = "Show Less")
#self._showbutton.grid(column=2,row=0,sticky=tk.W)
self._showless = True
else :
self._showbutton.configure(text = "Show More")
#self._showbutton.grid(column=2,row=0,sticky=tk.W)
self._showless = False
self._sequence = [1,2,3,29,5,7,21,15,6]
self._update_checkbuttons(
self.scrollable_frame.content_frame,self._sequence)
if __name__=="__main__" :
LARGE_FONT= ("Verdana", 12)
DISPLAY_KEYS_GEOMETRY='350x450'
root = tk.Tk()
show = DisplayKeys(root)
show.pack()
root.mainloop()
我真的很明白我的例子太大了。我有一个解决方法,我将显示。唯一的优点是它显示了定义类的价值,使破坏和替换可滚动框架变得容易。解决方案是销毁整个可滚动框架并重建它。我不明白为什么:self.content_frame.grid(列= 0,行= 0,粘性='nw',ipadx = 5,ipady = 5)第53行不起作用,但是这种解决方法可以让我继续前进。抱歉,如果有人在这个问题上花费了时间。
import tkinter as tk
from tkinter import ttk
import os
import inspect
import functools
import sys
class ScrollableFrame:
# https://blog.tecladocode.com/tkinter-scrollable-frame
def __init__(self,container):
self.container = container
self.top_frame = tk.Frame(container,height=2)
self.top_frame.configure(bg='gray15')
# create a frame to hold the Canvas andscrollbars
self.canvas = tk.Canvas(container,borderwidth=5)
self.canvas.configure(bg = 'orange')
self.content_frame = tk.Frame(self.canvas, bg = 'yellow')
#self.content_frame.grid_propagate(True)
# create a vertical scrollbar linked to the canvas
self.scrollbar = ttk.Scrollbar(self.canvas, orient="vertical", command=self.canvas.yview)
self.canvas.configure(yscrollcommand=self.scrollbar.set) # again scrollbar.set is a provided function
self.scrollbar.config(command=self.canvas.yview)
self.xscrollbar = ttk.Scrollbar(self.canvas, orient = 'horizontal', command=self.canvas.xview)
self.canvas.configure(xscrollcommand=self.xscrollbar.set)
self.xscrollbar.config(command=self.canvas.xview)
# before we are done we need to put buttons into ScrollableFame, row 0
# and populate the content_frame with widgets
# after this has been done, the bounding box must be created
container.bind(
"<Configure>",
lambda e: self.canvas.configure(
scrollregion=self.canvas.bbox("all")
)
)
def destroy(self):
self.top_frame.destroy()
self.canvas.destroy()
def finish(self):
self.container.config(bg = 'lightgreen')
self.top_frame.pack(side=tk.TOP,fill=tk.BOTH,expand=False)
#self.content_frame.pack(side=tk.TOP,fill = tk.BOTH,expand=False)
self.content_frame.grid_rowconfigure(0,weight=1)
self.content_frame.grid(column=0,row=0,sticky='nw',ipadx = 5,ipady=5)
self.canvas.create_window((0,0), window=self.content_frame)
self.canvas.pack(side=tk.TOP,fill=tk.BOTH,expand=False,ipady=10)
self.scrollbar.pack(fill='both',side='right',expand='false')
self.xscrollbar.pack(fill='both',side='bottom',expand='false')
self.canvas.update_idletasks()
self.canvas.yview_moveto(0)
self.canvas.xview_moveto(0)
class DisplayKeys(tk.Frame):
def __init__(self,parent,*args,**kwargs) :
tk.Frame.__init__(self,parent,*args,**kwargs)
self.keys_ = [f'display{i}' for i in range(30)]
self.parent = parent
self._showless = False
#self._checkbuttons_initialized = None
self.scrollable_frame = ScrollableFrame(parent)
self._label = tk.Label(self.scrollable_frame.top_frame,
text = "Key List",font = LARGE_FONT)
self._label.grid(column=0,row=0)
self._sequence = [1,2,3,29,5,7,21,15,6]
self._showbutton = tk.Button(self.scrollable_frame.top_frame,
text='Show More',
command=lambda:
self._showbutton_action())
self._showbutton.grid(column=2,row=0,padx=10,sticky=tk.N)
self._update_checkbuttons(self.scrollable_frame.content_frame,self._sequence )
def _update_checkbuttons(self,frame,seq):
#print(*seq)
# self._checkbuttons_initialized = True
self.checkVars = []
self.txtVars = []
searchVar = "Search"
self._checkbuttons = []
for i,place in enumerate(seq) :
bv = tk.BooleanVar()
tvar = tk.StringVar()
dn = self.keys_[place]
ck = tk.Checkbutton(frame,text=dn,variable=bv)
ck.grid(column=0,row=i,sticky='w')
ck.grid_rowconfigure(0,weight = 1)
self._checkbuttons.append(ck)
self.checkVars.append(bv)
txt = tk.Entry(frame,width = 30, textvariable = tvar)
txt.bind('<Return>',self._cmgo)
txt.grid(column = 1,row = i,sticky="nw")
txt.grid_rowconfigure(1,weight=2)
#txt.grid_rowconfigure(0,minsize=400,weight = 1)
#txt.grid_columnconfigure(0,weight=1)
self.txtVars.append(tvar)
self.scrollable_frame.finish()
def _cmgo(self):
pass
def _showbutton_action(self):
if not self._showless :
self._sequence = range(len(self.keys_))
button_text = "Show Less"
#self._showbutton.grid(column=2,row=0,sticky=tk.W)
self._showless = True
else :
button_text = "Show More"
#self._showbutton.grid(column=2,row=0,sticky=tk.W)
self._showless = False
self._sequence = [1,2,3,29,5,7,21,15,6]
self.scrollable_frame.destroy()
self.scrollable_frame = ScrollableFrame(self.parent)
self._label = tk.Label(self.scrollable_frame.top_frame,
text = "Key List",font = LARGE_FONT)
self._label.grid(column=0,row=0)
self._showbutton = tk.Button(self.scrollable_frame.top_frame,
text=button_text,
command=lambda:
self._showbutton_action())
self._showbutton.grid(column=2,row=0,padx=10,sticky=tk.N)
self._update_checkbuttons(self.scrollable_frame.content_frame,self._sequence)
if __name__=="__main__" :
LARGE_FONT= ("Verdana", 12)
DISPLAY_KEYS_GEOMETRY='350x450'
root = tk.Tk()
show = DisplayKeys(root)
show.pack()
root.mainloop()