2012-05-23 71 views
5

我使用TkInter創建了一些對話框,並且需要能夠在單擊父級按鈕時打開子窗口(模態或無模式)。然後,孩子將允許創建數據記錄,並且該數據(記錄或操作被取消)需要傳回給父窗口。到目前爲止,我有:如何在TkInter中創建子窗口並與父級進行通信

import sel_company_dlg 

from Tkinter import Tk 

def main(): 
    root = Tk() 
    myCmp = sel_company_dlg.SelCompanyDlg(root) 
    root.mainloop() 

if __name__ == '__main__': 
    main() 

這將調用頂層對話框,允許用戶選擇一個公司。該公司選擇對話框看起來是這樣的:

class SelCompanyDlg(Frame): 
    def __init__(self, parent): 
     Frame.__init__(self, parent) 
     self.parent_ = parent 
     self.frame_ = Frame(self.parent_) 
     // .. more init stuff .. 
     self.btNew_ = Button(self.frame_, text="New ...", command=self.onNew) 

    def onNew(self): 
     root = Toplevel() 
     myCmp = company_dlg.CompanyDlg(root) 

在點擊新建...按鈕,將顯示一個創建公司的對話框,允許用戶填寫公司的詳細信息,然後點擊創建或取消。這有一個開放位:

class CompanyDlg(Frame): 
    def __init__(self, parent): 
     Frame.__init__(self, parent) 
     // etc. 

我與調用子對話框中onNew()的最好辦法掙扎 - 我有什麼工作,但我不相信這是最好的辦法,另外,我可以」看看如何與孩子對話溝通細節。

我試過看網上教程/參考,但我發現是太簡單或重點是像tkMessageBox.showinfo()這不是我想要的東西。

回答

7

至少有一些方法可以解決您的問題。您的對話框可以直接將信息發送到主應用程序,或者您的對話框可以生成一個事件,通知主應用程序數據確實要從對話框中拉出。如果對話框簡單地改變某些東西的外觀(例如,字體對話框),我通常會生成一個事件。如果對話創建或刪除數據,我通常會將信息推送回應用程序。

我通常有一個應用程序對象,作爲整個GUI的控制器。通常這是與主窗口相同的類,或者它可以是一個單獨的類,甚至可以定義爲一個mixin。此應用程序對象具有對話框可以調用以將數據提供給應用程序的方法。

例如:

class ChildDialog(tk.Toplevel): 
    def __init__(self, parent, app, ...) 
     self.app = app 
     ... 
     self.ok_button = tk.Button(parent, ..., command=self.on_ok) 
     ... 
    def on_ok(self): 
     # send the data to the parent 
     self.app.new_data(... data from this dialog ...) 

class MainApplication(tk.Tk): 
    ... 

    def on_show_dialog(self): 
     dialog = ChildDialog(self) 
     dialog.show() 

    def new_data(self, data): 
     ... process data that was passed in from a dialog ... 

當創建對話框,該應用程序對象的引用傳遞。然後對話框知道調用該對象上的特定方法來將數據發送迴應用程序。

如果你不是整個模型/視圖/控制器的東西,你可以輕鬆地傳遞一個函數而不是一個對象,有效地告訴對話「當你想給我數據時調用這個函數」。

+0

非常感謝這一點,它確實幫助。 –

+0

#bryan-oakley好的技術總結。您是否推薦了關於這些技術(互聯網或書籍資源)的更多關於父母與子窗口之間數據交換的詳細信息? : - 事件生成回父 - 將數據推回父 - - ... – AJN

2

在我的一個項目中,我試圖在根窗口(self)的孩子tk.Toplevel窗口(child1)內檢查,如果用戶從根目錄創建了tk.Toplevel窗口(child2)窗口,並且此時該窗口(child2)出現在用戶屏幕上。

如果不是這種情況,新的tk.Toplevel窗口應該由根窗口的子窗口(child1)而不是根窗口本身創建。如果它已經由根窗口創建並且當前存在於用戶屏幕上,它應該獲得focus(),而不是通過「child1」重新初始化。

根窗口被包裝在名爲App()的類中,並且兩個「children」窗口都是由根類App()中的方法創建的。

如果給該方法的參數爲True,我必須在安靜模式下初始化「child2」。我想那是糾結的錯誤。這個問題發生在Windows 7 64位上,如果這很重要的話。

我想這(例如):

import tkinter as tk 
from tkinter import ttk 
class App(tk.Tk): 
    def __init__(self): 
     tk.Tk.__init__(self) 
     top = self.winfo_toplevel() 
     self.menuBar = tk.Menu(top) 
     top['menu'] = self.menuBar 
     self.menuBar.add_command(label='Child1', command=self.__create_child1) 
     self.menuBar.add_command(label='Child2', command=lambda: self.__create_child2(True)) 
     self.TestLabel = ttk.Label(self, text='Use the buttons from the toplevel menu.') 
     self.TestLabel.pack() 
     self.__create_child2(False) 

    def __create_child1(self): 
     self.Child1Window = tk.Toplevel(master=self, width=100, height=100) 
     self.Child1WindowButton = ttk.Button(self.Child1Window, text='Focus Child2 window else create Child2 window', command=self.CheckForChild2) 
     self.Child1WindowButton.pack() 

    def __create_child2(self, givenarg): 
     self.Child2Window = tk.Toplevel(master=self, width=100, height=100) 
     if givenarg == False: 
      self.Child2Window.withdraw() 
      # Init some vars or widgets 
      self.Child2Window = None 
     else: 
      self.Child2Window.TestLabel = ttk.Label(self.Child2Window, text='This is Child 2') 
      self.Child2Window.TestLabel.pack() 

    def CheckForChild2(self): 
     if self.Child2Window: 
      if self.Child2Window.winfo_exists(): 
       self.Child2Window.focus() 
      else: 
       self.__create_child2(True) 
     else: 
      self.__create_child2(True) 

if __name__ == '__main__': 
    App().mainloop() 

這裏談到的問題: 我無法檢查「的child2」已經存在。遇到錯誤:_tkinter.TclError:壞窗口路徑名

解決方案:

得到正確的「窗口路徑名」是,而不是調用winfo_exists()方法直接到「的child2」窗口的唯一途徑,調用「child1」窗口的主窗口並添加相應的屬性,然後添加要使用的主窗口的屬性。

例(該方法CheckForChild2的編輯):

def CheckForChild2(self): 
     if self.Child2Window: 
      if self.Child1Window.master.Child2Window.winfo_exists(): 
       self.Child1Window.master.Child2Window.focus() 
      else: 
       self.__create_child2(True) 
     else: 
      self.__create_child2(True) 
相關問題