Python,Tkinter:使用列表制作复选框网格

时间:2017-01-24 15:22:33

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

我试图创建一个具有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会为我调整屏幕大小所以我知道问题不在于制作小部件而是放置它们。

我做错了什么?

Shell输出:

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

2 个答案:

答案 0 :(得分:2)

小部件不会出现在屏幕上的第一个原因是因为它们位于一个框架中,而您从未将框架添加到主窗口。您需要在pack的实例上致电placegridApp

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

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

执行此操作时,您会发现窗口缩小到几个像素。这是因为place不会导致包含窗口扩展以适合其子项。这是记录在案的行为,并且是place通常不是做小部件布局的好选择的几个原因之一。如果要创建窗口小部件网格,grid是自然选择,当窗口调整大小时,可以很容易地做出正确的反应。

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

一旦您计算了尺寸,就可以在根窗口上使用geometry来强制它足够大:

root.geometry("200x200")

答案 1 :(得分:1)

我使用.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()

enter image description here

顺便说一句:如果您更喜欢将类别作为普通元组,那么您可以使用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()