2013-09-25 39 views
0

我想在Tkinter GUI中创建一堆子帧,每个子帧都包含一些用户输入变量,我需要稍后才能通过唯一每个子帧的ID。我需要能够添加和删除随意子帧,并让他们在一个合理的顺序ID'd(整数从1计数,此刻)添加和删除tkinter帧 - 跟踪实例

三个问题真的:

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

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

3)通常:有更好的方法来解决这个问题吗?在追踪帧实例的意义上。他们现在在列表中...我早些时候开始使用字典,但与...合作更难...有更好的建议吗?

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() 

谢谢... :)

回答

0

这里是我会做:

  1. 建立从FrameAllInstances继承(和重命名为类似 “FrameGroup”)。然后它变成一个“巨型小工具”,子框架可以直接控制。
  2. 使您的子帧成为Frame的子类(并将其称为“子帧”)。这也是“megawidget”,它需要被松耦合到其父(即:它不应该知道root.all_instances
  3. 有你的添加和删除按钮调用FrameGroup对象的方法

。我还建议做一个全球进口既然您同时使用TTK和Tkinter的,一会覆盖其他根据其命令对您订购的import语句

下面是与修改的工作,例如:。

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() 
+0

谢谢布莱恩。我想我可以看到你如何重组它的逻辑。你更简单的.pack()方法避免了获得正确列的问题,但连续的列和框架名称对我来说是必需的,所以我必须再次使用.grid()来查看。 Re:导入ttk并覆盖tkinter - 我很满意,并且不需要tk.widget或ttk.widget的清晰度(基于我实际使用的所有小部件都被覆盖,然后我可以不使用ttk样式额外的打字),但是我还有其他缺点吗? – Tom

+0

@Tom:包和网格与框架名称无关。至于其他缺点,我只是说,不做全球进口是最好的做法。另外,当您执行全局导入时,它会使代码更难理解。例如,我认为你使用的是tkinter按钮和标签,直到我弄清楚我的回答后才意识到你是依赖tkk进口来覆盖tk进口。如果你使用'ttk.Button'或者'tk.Button',你的代码很清楚你正在使用哪个小部件,并且在编写软件时清晰度应该是一个高优先级的目标。 –

+0

@Tom:如果你想要连续的列名,即使用户在中间删除了一列,一个简单的解决方案是给Subframe类添加一个'rename'方法,然后让'Remove'函数迭代所有这些实例使用每列所需的新名称进行重命名。 –