2013-09-25 71 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'函數迭代所有這些實例使用每列所需的新名稱進行重命名。 –