Python 带tkinter的超长检查表框

Python 带tkinter的超长检查表框,python,python-3.x,tkinter,checkbox,scrollbar,Python,Python 3.x,Tkinter,Checkbox,Scrollbar,我正在使用中的代码创建一个带有复选框的列表 import tkinter as tk root = tk.Tk() class ChecklistBox(tk.Frame): def __init__(self, parent, choices, **kwargs): tk.Frame.__init__(self, parent, **kwargs) self.vars = [] bg = self.cget(&quo

我正在使用中的代码创建一个带有复选框的列表

import tkinter as tk

root = tk.Tk()

class ChecklistBox(tk.Frame):
    def __init__(self, parent, choices, **kwargs):
        tk.Frame.__init__(self, parent, **kwargs)
        
        self.vars = []
        bg = self.cget("background")
        for choice in choices:
            var = tk.StringVar(value=choice)
            self.vars.append(var)
            cb = tk.Checkbutton(self, var=var, text=choice,
                                onvalue=choice, offvalue="",
                                anchor="w", width=20, background=bg,
                                relief="flat", highlightthickness=0
            )
            cb.pack(side="top", fill="x", anchor="w")
    
    
    def getCheckedItems(self):
        values = []
        for var in self.vars:
            value =  var.get()
            if value:
                values.append(value)
        return values

choices = [str(e) for e in range(100)]
checklist = ChecklistBox(root, choices, bd=1, relief="sunken", background="white")
checklist.pack()
由于选择列表很长,我想在列表中添加一个滚动条。最好的方法是什么



我尝试按照这个示例进行操作,但是
ChecklistBox
没有
yview
方法,也没有
yscrollcommand
选项。我不知道如何避免这个问题。

问题的根源在于帧不可滚动。因此,您必须找到一个支持滚动的小部件,并将其作为向一组小部件添加滚动的基础

Canvas
小部件通常用于此目的。它通常与内部框架结合使用,这样就很容易使用
pack
grid
来排列小部件。但是,因为您要创建一个相同小部件的垂直堆栈,所以直接在画布上绘制复选按钮更容易

第一步是向框架添加画布和滚动条:

class ChecklistBox(tk.Frame):
    def __init__(self, parent, choices, **kwargs):
        tk.Frame.__init__(self, parent, **kwargs)

        canvas = tk.Canvas(self, background=self.cget("background"))
        vsb = tk.Scrollbar(self, command=canvas.yview)
        canvas.configure(yscrollcommand=vsb.set)
        vsb.pack(side="right", fill="y")
        canvas.pack(side="left", fill="both", expand=True)
        ...
接下来,我们将调用
create\u window
,而不是在check按钮上调用
pack
。我们可以得到上一个项目的y坐标,以确定下一个项目的放置位置。我们将使用框架的
pady
选项来设置间距

    pady = int(str(self.cget("pady")))
    for choice in choices:
        ...
        bbox = canvas.bbox("all")
        y0 = pady if bbox is None else bbox[3]+pady
        canvas.create_window(0, y0, window=cb, anchor="nw")

你可以创建一个包含所有检查按钮的框架。我很好奇,如果我们直接继承
Canvas
,而不是继承
frame
,会有什么不同吗?@Saad:不会,不会有任何不同,尽管你不应该将滚动条打包在画布中。谢谢你的回复。我想我们可以跳过
Frame
,但是忘记了如果将滚动条打包在
Canvas
中会占用一些空间,这不是一个好的做法。第二块代码也是类定义的一部分吗?