Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create child window and communicate with parent in TkInter

Tags:

python

tkinter

I'm creating some dialogs using TkInter and need to be able to open a child sub-window (modal or modeless) on clicking a button in the parent. The child would then allow a data record to be created and this data (either the record or if the operation was cancelled) needs to be communicated back to the parent window. So far I have:

import sel_company_dlg

from Tkinter import Tk

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

if __name__ == '__main__':
    main()

This invokes the top level dialog which allows the user to select a company. The company selection dialog looks like this:

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)

On clicking the New ... button, a Create Company dialog is displayed which allows the user to fill in company details and click on create or cancel. Here's the opening bit of that:

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

I'm struggling with the best way of invoking the child dialog in onNew() - what I have works but I'm not convinced it's the best approach and also, I can't see how to communicate the details to and from the child dialog.

I've tried looking at online tutorials / references but what I've found is either too simplistic or focuses on things like tkMessageBox.showinfo() which iss not what I want.

like image 888
Component 10 Avatar asked May 23 '12 10:05

Component 10


1 Answers

There are at least a couple ways to solve your problem. Either your dialog can directly send information to the main application, or your dialog can generate an event that tells the main application that data is really to be pulled from the dialog. If the dialog simply changes the appearance of something (for example, a font dialog) I usually generate an event. If the dialog creates or deletes data I typically have it push information back to the application.

I typically have an application object that acts as the controller for the GUI as a whole. Often this is the same class as the main window, or it can be a separate class or even defined as a mixin. This application object has methods that dialogs can call to feed data to the application.

For example:

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 ...

When creating the dialog, you pass in a reference to the application object. The dialog then knows to call a specific method on this object to send data back to the application.

If you're not into the whole model/view/controller thing you can just as easily pass in a function rather than an object, effectively telling the dialog "call this function when you want to give me data".

like image 175
Bryan Oakley Avatar answered Oct 24 '22 09:10

Bryan Oakley