【问题标题】:Python, Tkinter: Making a grid of Checkboxes using ListsPython,Tkinter:使用列表制作复选框网格
【发布时间】:2017-01-24 15:22:32
【问题描述】:

我正在尝试制作一个具有 3x3 复选框网格的 tkinter 程序,我为此创建的代码是:

import tkinter as tk

class App(tk.Frame):
    def __init__(self,* args,** qwargs):
        tk.Frame.__init__(self)
        self.strCategories=("Q","W","E","R","T","Y","U","I","O")
        self.varCategories={}
        for x in self.strCategories:
            self.varCategories[x] = tk.IntVar()

        self.chckbxCategories={}
        for i in range(3):
            for j in range(3):
                var = self.varCategories[self.strCategories[i*3+j]]
                x=10/40 + 11*i/40
                y=7/20 + 4*j/20
                print(str(x),str(y))

                checkbox = tk.Checkbutton(self, text=self.strCategories[i*3+j], font=('Lucida Grande',15),
                                          anchor='w', bg='#FFFFFF', variable=var, onvalue=1, offvalue=0)
                checkbox.place(relx=x, rely=y, relwidth=10/40, relheight=5/20)
                self.chckbxCategories[self.strCategories[i*3+j]] = checkbox


app = App()
app.mainloop()

但是,小部件不会出现在屏幕上!如果我用其他几何管理器替换.place 它可以工作(我想使用.place,因为它的relxrely 为我处理调整屏幕大小)所以我知道问题不在于制作小部件,但放置它们。

我做错了什么?

外壳输出:

0.25 0.35
0.25 0.55
0.25 0.75
0.525 0.35
0.525 0.55
0.525 0.75
0.8 0.35
0.8 0.55
0.8 0.75

【问题讨论】:

  • 也许使用二维列表/元组self.strCategories = [ ["Q","W","E"] , ["R","T","Y"] , ["U","I","O"] ]然后你就不需要range(3)
  • 它将更具可读性 cb = tk.Checkbutton()cb.place()self.chckbxCategories[...] = cb
  • 你使用 Python 2 吗?然后10/40 给出0,而不是0.25。最好使用print 来检查分配给relxrely 等的值。
  • 我认为问题在于place(relx=10/4 + 11*i/4, ...),relx这里大于一,所以在窗外。
  • 不要在一行中放这么多代码。使用临时变量。例如,计算 relx 和依赖值并将值存储在变量中。这样您就可以检查这些值是否符合您的预期(可能不是)。

标签: python python-3.x loops checkbox tkinter


【解决方案1】:

小部件未出现在屏幕上的第一个原因是它们位于框架中,而您从未将框架添加到主窗口中。您需要在App 的实例上调用packplacegrid

与问题无关但与良好的编码实践相关,您应该显式创建根窗口。将代码的最后几行更改为如下所示:

root = tk.Tk()
app = App(root)
app.pack(fill="both", expand=True)
app.mainloop()

当您这样做时,您现在会注意到您的窗口缩小到只有几个像素。这是因为place 不会导致包含窗口扩展以适应其子级。这是记录在案的行为,也是place 通常不是进行小部件布局的好选择的几个原因之一。如果您正在创建一个小部件网格,grid 是自然的选择,它可以很容易地在窗口调整大小时做出正确的反应。

话虽如此,要在使用 place 时查看小部件,您需要强制包含框架或主窗口足够大以适应它。您必须计算这个大小,这也是为什么place 不是最佳选择的另一个原因。

计算出大小后,您可以在根窗口上使用geometry 来强制它足够大:

root.geometry("200x200")

【讨论】:

    【解决方案2】:

    我使用.grid(... , sticky='news')columnconfigure(..., weight=1) 来获得相同的结果(我希望因为我无法运行您的代码来查看预期结果)。

    我将类别保留为二维元组,因此我可以轻松使用 for 循环和 item - 无需所有这些 i*3+jself.strCategories[i*3+j]

    我在同一个循环中创建IntVar()。而且我使用临时的varcb,所以它更具可读性。

    import tkinter as tk
    
    root = tk.Tk()
    
    str_categories = ( ("Q","W","E"), ("R","T","Y"), ("U","I","O") )
    
    var_categories = {}
    chckbx_categories = {}
    
    for r, row in enumerate(str_categories):
    
        root.columnconfigure(r, weight=1)
        root.rowconfigure(r, weight=1)
    
        for c, item in enumerate(row):
            var = tk.IntVar()
    
            cb = tk.Checkbutton(root, text=item, variable=var, onvalue=1, offvalue=0,
                                font=('Lucida Grande',15), anchor='w', bg='#FFFFFF')
            cb.grid(row=r, column=c, sticky='news')
    
            var_categories[item] = var
            chckbx_categories[item] = cb
    
    root.mainloop()
    


    顺便说一句:如果您宁愿需要类别作为普通元组,那么您可以使用range(3)item = str_categories[r*3+c],但其余部分相同。

    import tkinter as tk
    
    root = tk.Tk()
    
    str_categories = ("Q", "W", "E", "R", "T", "Y", "U", "I", "O")
    
    var_categories = {}
    chckbx_categories = {}
    
    for r in range(3):
    
        root.columnconfigure(r, weight=1)
        root.rowconfigure(r, weight=1)
    
        for c in range(3):
            item = str_categories[r*3+c]
    
            var = tk.IntVar()
    
            cb = tk.Checkbutton(root, text=item, variable=var, onvalue=1, offvalue=0,
                                font=('Lucida Grande',15), anchor='w', bg='#FFFFFF')
            cb.grid(row=r, column=c, sticky='news')
    
            var_categories[item] = var
            chckbx_categories[item] = cb
    
    root.mainloop()
    

    或者你可以创建"iterator"

    iterator = iter(str_categories)
    

    然后你可以通过

    得到"next"项目
    item = next(iterator)
    

    完整版:

    import tkinter as tk
    
    root = tk.Tk()
    
    str_categories = ("Q", "W", "E", "R", "T", "Y", "U", "I", "O")
    
    iterator = iter(str_categories)
    
    var_categories = {}
    chckbx_categories = {}
    
    for r in range(3):
    
        root.columnconfigure(r, weight=1)
        root.rowconfigure(r, weight=1)
    
        for c in range(3):
            item = next(iterator)
    
            var = tk.IntVar()
    
            cb = tk.Checkbutton(root, text=item, variable=var, onvalue=1, offvalue=0,
                                font=('Lucida Grande',15), anchor='w', bg='#FFFFFF')
            cb.grid(row=r, column=c, sticky='news')
    
            var_categories[item] = var
            chckbx_categories[item] = cb
    
    root.mainloop()
    

    【讨论】:

    • 这没关系,但我的代码的重点是屏幕上会有其他东西,我希望这些复选框可以根据屏幕宽度进行调整
    猜你喜欢
    • 2015-10-03
    • 1970-01-01
    • 2013-01-11
    • 2012-12-30
    • 1970-01-01
    • 1970-01-01
    • 2021-11-25
    • 1970-01-01
    • 2019-04-16
    相关资源
    最近更新 更多