python - Python Tkinter 滚动条和框架未显示所有复选框
问题描述
一些 tkinter 代码有问题,我相信我离它太近了,看不到我面前的问题。我正在将复选框加载到框架中并将滚动条附加到该位置。
在我达到 1000 多个复选框之前,这很有效。然后它似乎被切断了,即使框架扩展了适合所有复选框的高度,它也没有在 gui 中显示它们。您可以在此处的图片中看到他们停止显示复选框故障的位置
这是我的代码:(请原谅它看起来有多乱,它是更大代码集的子集,我刚刚隔离了错误)
from tkinter import *
build_vars = {}
build_Radios = []
parent = Tk()
center_container = Frame(parent, width=5, height=5)
center_container.grid(row=1, sticky="nsew")
# Center Row Columns
center_center_container = Frame(center_container, width=150, height=200)
center_center_container.grid(row=0, column=2, sticky="ns")
build_canvas = Canvas(center_center_container, background='green')
build_canvas.grid(row=0, column=0, sticky=N+E+W+S)
# Create a vertical scrollbar linked to the canvas.
vsbar = Scrollbar(center_center_container, orient=VERTICAL, command=build_canvas.yview)
vsbar.grid(row=0, column=1, sticky=NS)
build_canvas.configure(yscrollcommand=vsbar.set)
# Create a frame on the canvas to contain the buttons.
frame_buttons = Frame(build_canvas, bd=2, background='red')
def create_build_radios():
# for index, item in enumerate(filtered_builds):
for index, item in enumerate(list(range(3000))):
build_vars[item] = IntVar()
radio = Checkbutton(frame_buttons, text=item, variable=build_vars[item], onvalue=1,
offvalue=0,
command=lambda item=item: sel(item))
radio.grid(row=index, column=0, sticky=W)
build_Radios.append(radio)
# Create canvas window to hold the buttons_frame.
build_canvas.create_window((0, 0), window=frame_buttons, anchor=NW)
build_canvas.update_idletasks() # Needed to make bbox info available.
bbox = build_canvas.bbox(ALL) # Get bounding box of canvas with Buttons.
build_canvas.configure(scrollregion=bbox, width=150, height=400)
def sel(item):
print(item)
create_build_radios()
parent.mainloop()
解决方案
所以这是更好的解决方案(比另一个更好,可以很容易地在上面放置更多的小部件,但请注意可能存在某种限制(至少是 CPU 的能力):
from tkinter import Tk, Canvas, Frame, Label, Scrollbar, Button, DoubleVar, StringVar, Entry
from tkinter.ttk import Progressbar
class PagedScrollFrame(Frame):
def __init__(self, master, items_per_page=100, **kwargs):
Frame.__init__(self, master, **kwargs)
self.master = master
self.items_per_page = items_per_page
self.pages = None
self.id_list = []
self.bbox_tag = 'all'
self._loading_frame = Frame(self)
self.__load_progress_tracker = DoubleVar(master=self.master, value=0.0)
self.__percent_tracker = StringVar(master=self.master, value='0.00%')
self.frame = Frame(self)
self.frame.pack(side='top', padx=20, pady=20)
self.canvas = Canvas(self.frame)
self.canvas.pack(side='left')
self.bg_label = Label(self.canvas)
self.bg_label.place(x=0, y=0, relwidth=1, relheight=1)
self.scrollbar = Scrollbar(self.frame, orient='vertical', command=self.canvas.yview)
self.scrollbar.pack(side='right', fill='y')
self.canvas.config(yscrollcommand=self.scrollbar.set)
self.canvas.bind('<Configure>',
lambda e: self.canvas.config(
scrollregion=self.canvas.bbox(self.bbox_tag)
))
self.button_frame = Frame(self)
self.button_frame.pack(fill='x', side='bottom', padx=20, pady=20)
self.canvas_frame = Frame(self.button_frame)
self.button_canvas = Canvas(self.canvas_frame, height=20)
self.button_canvas.pack(expand=True)
self.inner_frame = Frame(self.button_canvas)
self.button_canvas.create_window(0, 0, window=self.inner_frame, anchor='nw')
self.button_scrollbar = Scrollbar(self.canvas_frame,
orient='horizontal',
command=self.button_canvas.xview)
self.button_scrollbar.pack(fill='x')
self.button_canvas.config(xscrollcommand=self.button_scrollbar.set)
self.button_canvas.bind(
'<Configure>', lambda e: self.button_canvas.config(
scrollregion=self.button_canvas.bbox('all')
)
)
def pack_items(self):
if not self.pages:
return
self._loading_frame.place(x=0, y=0, relwidth=1, relheight=1)
self._loading_frame.lift()
self._loading_frame.update_idletasks()
self.after(100, self._pack_items)
def _pack_items(self):
Label(self._loading_frame, text='Loading...').pack(expand=True)
Progressbar(self._loading_frame,
orient='horizontal',
variable=self.__load_progress_tracker,
length=self._loading_frame.winfo_width()
- self._loading_frame.winfo_width() // 10).pack(expand=True)
Label(self._loading_frame, textvariable=self.__percent_tracker).pack(expand=True)
self.update_idletasks()
widgets = [widget for page in self.pages for widget in page.winfo_children()]
length = len(widgets)
self.after(100, self.__pack_items, widgets, 0, length)
def __pack_items(self, widgets, index, length):
if index >= length:
self._loading_frame.destroy()
self.canvas.config(scrollregion=self.canvas.bbox('all'))
return
widgets[index].pack()
percent = (index + 1) * 100 / length
self.__load_progress_tracker.set(value=percent)
self.__percent_tracker.set(value=f'{percent: .2f}%')
self.after(1, self.__pack_items, widgets, index + 1, length)
def change_frame(self, index):
if not self.pages:
return
self.bbox_tag = self.id_list[index]
self.canvas.config(scrollregion=self.canvas.bbox(self.bbox_tag))
self.bg_label.lift()
self.pages[index].lift()
def create_pages(self, num_of_items, items_per_page=None):
self.pages = None
if not items_per_page:
items_per_page = self.items_per_page
num_of_pages = num_of_items // items_per_page
if num_of_items % items_per_page != 0:
num_of_pages += 1
start_indexes = [items_per_page * page_num for page_num in range(num_of_pages)]
end_indexes = [num + items_per_page for num in start_indexes]
end_indexes[-1] += (num_of_items % items_per_page
- (items_per_page if num_of_items % items_per_page != 0 else 0))
self.pages = [Frame(self.canvas) for _ in range(num_of_pages)]
self.id_list = []
for page, frame in enumerate(self.pages):
self.id_list.append(self.canvas.create_window(0, 0, window=frame, anchor='nw'))
self.pages[0].lift()
if num_of_pages >= 2:
Button(self.button_frame, text='1',
command=lambda: self.change_frame(0)).pack(
side='left', expand=True, fill='both', ipadx=5
)
if num_of_pages > 2:
self.canvas_frame.pack(fill='x', expand=True, side='left')
for page_num in range(1, num_of_pages - 1):
Button(self.inner_frame, text=page_num + 1,
command=lambda index=page_num: self.change_frame(index)).pack(
expand=True, fill='both', side='left', ipadx=5
)
Button(self.button_frame, text=num_of_pages,
command=lambda: self.change_frame(num_of_pages - 1)).pack(
side='right', fill='both', expand=True, ipadx=5
)
return zip(start_indexes, end_indexes, self.pages)
def create_paged_canvas():
scroll = PagedScrollFrame(root)
scroll.pack()
lst = tuple(range(3000))
for start, end, parent in scroll.create_pages(len(lst)):
for i in lst[start:end]:
frame_ = Frame(parent)
Label(frame_, text=str(i).zfill(4)).pack(side='left')
scroll.pack_items()
root = Tk()
root.protocol('WM_DELETE_WINDOW', exit)
create_paged_canvas()
root.mainloop()
主要信息:
基本上这会创建分页的可滚动画布。所需要的只是调整create_paged_canvas()
函数中的内部循环和可迭代对象。您还可以调整每页显示多少项目(这也允许以后配置,例如在菜单中您可以调用类似的create_paged_canvas()
函数并将items_per_page
参数更改为其他内容(将不得不再次加载所有内容但是......tkinter
是tkinter
,它非常慢,更糟糕的是它不允许直接使用线程,甚至不能谈论进程(那些东西会加快速度,但根本无法完成)))
重要(建议):
我强烈建议不要在导入某些东西时使用通配符(*
),你应该导入你需要的东西,例如from module import Class1, func_1, var_2
等等或导入整个模块:import module
然后你也可以使用别名:import module as md
或者类似的东西,重点除非您真正知道自己在做什么,否则不要导入所有内容;名称冲突是问题所在。
杂项:
为了获得更好的性能,最好不要创建标签,而是直接在画布上创建文本(使用其他解决方案)或使用列表框,以防您需要显示大量数据,因为它会加快速度因为不必创建小部件(这也意味着您只能查看几乎所有数据)
如果您有任何问题,请务必提出这些问题!
推荐阅读
- android - Android log cat 不为发布版本编写调试日志
- r - 当输入是 Shiny 中的值列表时如何从缓存中提取计算值
- python - 从 django python 中的 ckeditor 获取选定的文本
- python - TensorFlow 接受哪些图像格式?我有一个 plt.image.AxesImage,我想将其转换为图像而不保存,用于训练集
- python - 使用 lxml 获取特定元素属性
- reinforcement-learning - 在强化学习 REINFORCE 算法中,我们可以将精度的指数作为奖励吗?
- javascript - JavaScript 抛出未捕获的语法错误:意外标记(switch 语句中的情况)
- reactjs - dispatchAction 将如何更新 react 17 中的当前 Fiber
- microservices - Kafka 消费者微服务在启动时卡住
- testing - “这个。
" 开玩笑地未定义