2013-09-25 4 views
0

Tkinter GUI에 일련의 하위 프레임을 만들려고합니다. 각각의 고유 한 입력 변수는 나중에 고유 한 인터페이스를 통해 얻을 수 있어야합니다. 각 서브 프레임에 대한 ID. 나는tkinter 프레임 추가 및 제거 - 인스턴스 추적 유지

세 가지 질문에 정말 (정수 순간에, 1 카운트 업) 추가하고 의지의 서브 프레임을 삭제하고 그들을 분별 위해 신원을 가질 수 있어야합니다 :

1) 특히, 각 프레임의 제목을 보여주는 Label 위젯이 표시되지 않는 이유는 무엇입니까? (아마도 이것은 어리석은 일입니다 ...)

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. Frame에서 AllInstances 상속을 확인 (그리고 "FrameGroup"같은 것으로 이름 변경). 그런 다음 서브 프레임이 직접 제어 할 수있는 자식 인 "메가 위젯"이됩니다.
  2. 서브 프레임을 Frame의 하위 클래스로 지정하고 "서브 프레임"이라고합니다. 이것은 또한 "megawidget"이며, loosly 즉 부모 (결합 될 필요가있다 : 그것은 약 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() 
+0

Bryan에게 감사드립니다. 나는 당신이 그것을 재구성 한 방법의 논리를 볼 수 있다고 생각합니다. 좀 더 단순한 .pack() 접근법은 올바른 열을 가져 오는 문제를 피할 수 있지만 연속 열과 프레임 이름이 필요할 것이므로 .grid()를 사용하여 다시 살펴보아야 할 것입니다. Re : ttk 가져 오기 및 tkinter 덮어 쓰기 - 나는 그걸로 행복했고 tk.widget 또는 ttk.widget의 선명도가 필요하지 않았습니다. (사실상 모든 위젯이 오버라이드 된 것을 기초로 다음 ttk 스타일을 사용할 수 있습니다. 추가 타이핑). 그러나 내가 알아야 할 다른 단점이 있습니까? – Tom

+0

@Tom : 팩과 격자는 프레임 이름과 아무 관련이 없습니다. 다른 단점에 관해서는, 나는 세계적인 수입을하지 않는 것이 가장 좋습니다. 또한 전역 가져 오기를 수행 할 때 코드를 이해하기 어렵게 만듭니다. 예를 들어, 당신이 tkinter 버튼과 라벨을 사용하고 있다고 가정했는데, tk 가져 오기를 무시하고 ttk 가져 오기에 의존한다는 것을 알았을 때까지 대답을 다듬을 때까지는 그렇지 않았습니다. 'ttk.Button' 또는'tk.Button'을 사용하면 코드를 사용하는 도구가 무엇인지 명확하게 알 수 있으며, 소프트웨어 작성시 명확성이 최우선 목표가되어야합니다. –

+0

@Tom : 사용자가 중간에있는 열을 삭제할 때도 연속 된 열 이름을 원한다면, 쉬운 해결책은'Subframe' 클래스에'rename' 메소드를 추가 한 다음'Remove' 함수를 각 열에 대해 원하는 새 이름으로 이름 바꾸기를 호출하는 인스턴스. –