1

我正在尝试在 Tkinter GUI 中创建一堆子帧,每个子帧都包含一些用户输入变量,稍后我需要通过每个子帧的唯一 ID 来获取这些变量。我需要能够随意添加和删除子帧,并以合理的顺序对它们进行标识(目前从 1 开始计数的整数)

三个问题:

1)具体来说,为什么显示每个框架标题的标签小部件不显示?(这可能是愚蠢的事情......)

2) 具体来说,为什么有时需要按两次添加或删除按钮来添加或删除框架?

3)一般来说:有没有更好的方法来解决这个问题?在跟踪框架实例的意义上。他们现在在一个列表中......我早些时候开始使用 dict 但它更难使用......有更好的建议吗?

from tkinter import *
from tkinter.ttk import *

class AllInstances(Tk):
    def __init__(self):
        Tk.__init__(self)
        self.master_frame = Frame(self)
        self.master_frame.grid()
        self.all_instances = []

root = AllInstances()

class OneInstance():
    def __init__(self):
        self.number = len(root.all_instances) + 1

        var1 = StringVar()
        var2 = StringVar()
        var3 = StringVar()

        self.sub_frame = Frame(root.master_frame)
        self.sub_frame.grid(column = self.number, row = 0)

        titletext = StringVar()
        titletext.set('%s %s' % ('Frame', self.number))
        print(titletext.get())
        title = Label(self.sub_frame, textvariable = titletext)
        title.grid() #work out why this label does not display!

        uservar1 = Entry(self.sub_frame, textvariable = var1)
        uservar1.grid()
        uservar2 = Entry(self.sub_frame, textvariable = var2)
        uservar2.grid()
        uservar3 = Entry(self.sub_frame, textvariable = var3)
        uservar3.grid()
        #etc etc

        add_button = Button(self.sub_frame, text = 'Add', command = lambda: Create())
        add_button.grid()

        def RemoveInstance(self):
            if len(root.all_instances) > 1:
                root.all_instances.remove(self)
                self.sub_frame.destroy()

                for instance in root.all_instances:
                    instance.number = (root.all_instances.index(instance) + 1)
            else:
                pass

        remove_button = Button(self.sub_frame, text = 'Remove', command = lambda: RemoveInstance(self))
        remove_button.grid()

        root.all_instances.append(self)

def Create():
    OneInstance()

Create()
root.mainloop()

谢谢... :)

4

1 回答 1

1

这是我要做的:

  1. AllInstances继承自(并重命名为“ FrameGroup Frame”之类的名称)。然后它变成一个“megawidget”,子帧是它可以直接控制的子帧。
  2. 使您的子框架成为Frame(并称其为“子框架”)的子类。这也是一个“megawidget”,它需要松散耦合到它的父级(即:它不应该知道root.all_instances
  3. 让您的添加和删除按钮调用 FrameGroup 对象上的方法。

我还建议不要进行全局导入。由于您同时使用 ttk 和 tkinter,因此其中一个将覆盖另一个,具体取决于您订购导入语句的顺序。

这是一个带有这些修改的工作示例:

import tkinter as tk

class FrameGroup(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
        self.all_instances = []
        self.counter = 0

    def Add(self):
        self.counter += 1
        name = "Frame %s" % self.counter 
        subframe = Subframe(self, name=name)
        subframe.pack(side="left", fill="y")
        self.all_instances.append(subframe)

    def Remove(self, instance):
        # don't allow the user to destroy the last item
        if len(self.all_instances) > 1:
            index = self.all_instances.index(instance)
            subframe = self.all_instances.pop(index)
            subframe.destroy()

    def HowMany(self):
        return len(self.all_instances)

    def ShowMe(self):
        for instance in self.all_instances:
            print(instance.get())

class Subframe(tk.Frame):
    def __init__(self, parent, name):
        tk.Frame.__init__(self, parent)
        self.parent = parent
        self.e1 = tk.Entry(self)
        self.e2 = tk.Entry(self)
        self.e3 = tk.Entry(self)
        label = tk.Label(self, text=name, anchor="center")
        add_button = tk.Button(self, text="Add", command=self.parent.Add)
        remove_button = tk.Button(self, text="Remove", command=lambda: self.parent.Remove(self))

        label.pack(side="top", fill="x")
        self.e1.pack(side="top", fill="x")
        self.e2.pack(side="top", fill="x")
        self.e3.pack(side="top", fill="x")
        add_button.pack(side="top")
        remove_button.pack(side="top")

    def get(self):
        return (self.e1.get(), self.e2.get(), self.e3.get())

class GUI(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.master_frame = tk.Frame(self)
        self.master_frame.grid()
        self.all_instances = FrameGroup(self.master_frame)
        self.all_instances.grid()

        # create the first frame
        self.all_instances.Add()

root = GUI()
root.mainloop()
于 2013-09-25T15:55:14.737 回答