0

I am rewriting a Tkinter program of mine and I want to separate the logic and UI into two different files: main.py, ui.py

In main we have a class MainApp() which handles all of the core functionality of the program.

In ui we have a class BaseApp() which is responsible for rendering the UI and doing all of those kind of things.

I have BaseApp() be a child of MainApp(), like this:

main.py

class MainApp():
    def __init__(self):
    #some code here

ui.py

import main
class BaseApp(main.MainApp):
    def __init__(self):
        main.MainApp.__init__(self)
        #render UI here e.g...
        mybtn = tkinter.Button(self.root, text="Hey StackOverflow", command=main.myFunction)

This all works fine. I got a long way into making this system without any issues... then I hit an issue.

I want to be able to call UI code from main. I need functions in the MainApp() class in the main module to be able to display popups and create Toplevel windows defined in classes in the ui module.

If MainApp() derives from BaseApp() then I can display the popups but the UI has access to none of the main features. If BaseApp() derives from MainApp() as above then the UI can access the logic but I cannot create any windows, e.g. ui.ProgressWindow, ui.Alert from the main module when I need to.

kylieCatt
  • 10,672
  • 5
  • 43
  • 51
Ilmiont
  • 2,032
  • 4
  • 27
  • 44
  • possible duplicate of [Circular import dependency in Python](http://stackoverflow.com/questions/1556387/circular-import-dependency-in-python) – NDevox May 28 '15 at 16:05
  • this is a circular import dependency. In short, there are some "clever" things you can do to get around them. But you shouldn't really. It makes the code far more confusing and you should really evaluate why you have split the classes into separate files and whether they should be put back together. – NDevox May 28 '15 at 16:06

1 Answers1

1

The solution would be to import the UI module from main, and initialize BaseApp() inside the constructor of MainApp() while passing it a reference to self that BaseApp can later use to reference the logic functions. MainApp would also retain a reference to BaseApp that it can use to call UI functions.

class MainApp:
    def __init__(self):
        self.UI = BaseApp(self)

Update: In response to the circular import issue, it probably is best to put both classes in the same file. The functionality would still remain the same since the logic and UI functions would still be in different classes.

Parker Hoyes
  • 2,118
  • 1
  • 23
  • 38
  • This only seems to work one way actually or I'm doing something wrong. UI->Main works well, but calling Main-> UI doesn't e.g. self.ui = BaseApp(self), then going self.ui.alert("message") I get AttributeError: "MainApp" object has no attribute "ui" – Ilmiont May 28 '15 at 16:16
  • @Ilmiont The code above should work. Make sure the instance of MainApp is always maintained and no functions are being called statically. – Parker Hoyes May 28 '15 at 16:58