如何在for循环中创建未知数量的TKinter对象

时间:2019-10-28 22:52:11

标签: python tkinter

我在TKinter中有一个滚动框。以及我要使用for循环从列表(由SQlite管理)从数据库中获取的每个元组的列表,其中我想在滚动框中创建一行小部件。该行包括行号,一个复选框,取自元组的标题和一个打开取自元组的链接的按钮。我遇到的问题是,我不知道如何在TKinter中创建未知数量的小部件行,也无法引用它们。以下代码的工作方式是创建行等,但是一旦创建行,我将无法引用单个窗口小部件。这很重要,因为单击复选框需要更新数据库中的IsActive列(也欢迎提供帮助)。我曾尝试使用字典来保存StringVar()的复选框,但我确定我做错了。

类本身是TKinter窗口中的框架。我很高兴这是一个初学者,这可能是一个愚蠢的问题

class details(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="details", font=controller.title_font)
        label.pack(side="top", fill="x", pady=10)
        button = tk.Button(self, text="Go to the start page",
                           command=lambda: controller.show_frame("StartPage"))
        button.place(relx=0.5, rely=0.95, anchor = tk.CENTER)

        myframe= tk.Frame(self,relief=tk.GROOVE,bd=1)
        myframe.place(relx=0.5, rely=0.45, anchor = tk.CENTER, width = 750, height = 450)

        self.canvas=tk.Canvas(myframe)
        self.frame=tk.Frame(self.canvas)
        myscrollbar=tk.Scrollbar(myframe,orient="vertical",command=self.canvas.yview)
        self.canvas.configure(yscrollcommand=myscrollbar.set)

        myscrollbar.pack(side="right",fill="y")
        self.canvas.pack(side="left", fill="both")
        self.canvas.create_window((0,0),window=self.frame,anchor='nw')
        self.frame.bind("<Configure>",self.myfunction)
        self.data()

    def data(self):
        lock.acquire(True)
        c.execute("select * from story")
        lock.release()
        results = c.fetchall()
        print(results)
        i = 0
        checkbuttons = {}
## the for loop where rows are created.
        for item in results:

            checkbuttons[item[0]] = tk.IntVar()
            b = item[4]
            s = tk.StringVar()
            tk.Label(self.frame,text=i).grid(row=i,column=0)
            tk.Checkbutton(self.frame, text="", variable=checkbuttons[item[0]], onvalue=1, offvalue=0).grid(row=i,column=1)

            tk.Label(self.frame,textvariable=s, width = 90).grid(row=i,column=2, sticky=tk.W)
            tk.Button(self.frame,text="LINK", command=lambda a = b: self.open_link(a)).grid(row=i,column=3)
            s.set(str(item[3]))
            i+=1
    def myfunction(self, event):
        self.canvas.configure(scrollregion=self.canvas.bbox("all"),width=750,height=500)

    def open_link(self, link):
        print(link)
        webbrowser.open(link, new=1)

1 个答案:

答案 0 :(得分:0)

  

我遇到的问题是,我不知道如何在TKinter中创建未知数量的小部件行,也无法引用它们。

最简单的解决方案是将它们放在列表或字典中,或者在您的情况下,放在字典列表中,其中列表中的每一行都是包含您要记住的数据的字典。

因此,从要记住的数据开始。在您的情况下,我猜测我们希望能够获取href,并且希望能够获取或设置关联的变量。

在以下示例中,我尝试使用比bi等更明智的变量名,并通过逻辑功能组织代码:从项目中提取数据,创建小部件,布置小部件,然后保存数据。

for rownum, item in enumerate(results):
    title = item[3]
    href = item[4]

    var = tk.IntVar(value=0)
    row_label = tk.Label(self.frame, text=rownum)
    title_label = tk.Label(self.frame, text=title)
    cb = tk.Checkbutton(self.frame, text="", variable=var,
                        onvalue=1, offvalue=0)
    button = tk.Button(self.frame, text="LINK",
                       command=lambda rownum=rownum: self.open_link(rownum))

    row_label.grid(row=rownum, column=0)
    cb.grid(row=rownum, column=1)
    title_label.grid(row=rownum, column=2, sticky="w")
    button.grid(row=rownum, column=3)

    # store the data in a dictionary so we can reference it later
    row = {
        "href": href,
        "var": var
    }
    self.rows.append(row)

出于说明目的,我修改了open_link以接受行号而不是链接。我们可以使用行号来访问href,我也让它自动选择关联的复选按钮以证明您可以。

def open_link(self, rownum):
    link = self.rows[rownum]['href']
    self.rows[rownum]['var'].set(1)
    print(link)