繁体   English   中英

如何在TkInter中创建子窗口并与父进行通信

[英]How to create child window and communicate with parent in 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()onNew()中调用子对话框的最佳方式 - 我有什么工作,但我不相信这是最好的方法,而且,我也看不出如何与孩子沟通细节对话。

我已经尝试过查看在线教程/参考资料,但我发现它要么过于简单化,要么专注于像tkMessageBox.showinfo()这样的东西,这不是我想要的。

至少有几种方法可以解决您的问题。 您的对话框可以直接将信息发送到主应用程序,或者您的对话框可以生成一个事件,告诉主应用程序确实要从对话框中提取数据。 如果对话框只是改变了某些东西的外观(例如,字体对话框),我通常会生成一个事件。 如果对话框创建或删除数据,我通常会将信息推送回应用程序。

我通常有一个应用程序对象作为整体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 ...

创建对话框时,传入对应用程序对象的引用。 然后,对话框知道在此对象上调用特定方法以将数据发送回应用程序。

如果你没有进入整个模型/视图/控制器的东西,你可以轻松地传入一个函数而不是一个对象,有效地告诉对话框“当你想给我数据时调用这个函数”。

在我的一个项目中,我试图在我的根窗口(自己)的子tk.Toplevel窗口(child1)内检查,如果用户在根窗口内创建了tk.Toplevel窗口(child2),并且此窗口(child2)此时出现在用户屏幕上。

如果不是这种情况,则新的tk.Toplevel窗口应该由根窗口的子窗口(child1)创建,而不是根窗口本身。 如果它已经由根窗口创建并且当前存在于用户屏幕上,则应该获得focus()而不是由“child1”重新初始化。

根窗口包含在一个名为App()的类中,两个“子”窗口都是由根类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)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM