0

My program starts with a 'Loading_UI' class that shows a simple loading bar and creates an object that contains data fetched from .csv files.

When the loading (= data fetching) is completed, the loading bar destroys itself (root.destroy()) and then I want to pass on the object that I created to another class that will show the main UI of the program. To keep things neat, I want to call the main UI from its own .py file and own Main_UI class.

Using the idea above, my question is: how can I pass the object on from the Loading_UI class to the Main_UI class?

(Run the program from RUN_loading.py)

(DataBase.py) Simple object creation:

class DataBase:

    def __init__(self, name):
        self.name = name

    def show_content(self):
        print(self.name)

And in the other .py file with class Loading_UI, something like this:

(RUN_Loading.py) UI with loading bar simulation:

from tkinter import *
from DataBase import DataBase

class Loading_UI:

    def __init__(self, master):

        self.master = master
        self.DataBase = DataBase("This is our object.")
        self.load_pct = DoubleVar()
        self.load_pct.set(0)
        loading_bar = Label(textvariable = self.load_pct)
        loading_bar.grid()

        self.handle_loading_progress()

    def handle_loading_progress(self):

        if self.load_pct.get() < 10:
            self.load_pct.set(self.load_pct.get() + 1)
            self.master.after(200, self.handle_loading_progress)
        else:
            self.show_main()

    def show_main(self):

        root.destroy()
        from UI_Main import Main_UI
        Main = Main_UI(self.DataBase)
        Main.main()

root = Tk()
root.geometry("100x100+300+300")
app = Loading_UI(root)
root.mainloop()

And the main UI which would need to process the object would look like this.

(UI_Main.py) Main UI Window that pops up after loading is complete.

from tkinter import *

class Main_UI:

    def __init__(self, database_object):

        self.DataBase = database_object

        # Run this function to check that the 
        # data object is properly received.
        self.DataBase.show_content()

root = Tk()
app = Main_UI(root, database_object)
root.mainloop()

if __name__ == '__main__':
    main()

The above is obviously wrong, but I just want to present the idea what I am after. Running the code above gives:

NameError: name 'database_object' is not defined

EDIT: Edited the code with a practical (simplified) example.

Nae
  • 14,209
  • 7
  • 52
  • 79
El Fred
  • 330
  • 1
  • 7
  • 23
  • There should probably be a single class that starts both the `Loading_UI` and the `Main_UI` that would facilitate passing an object from one to the other. – chepner Jan 15 '18 at 16:39
  • Can't the same be done across different .py files, each with their own class? It's easier to maintain and gives much shorter code. – El Fred Jan 15 '18 at 16:47
  • So where does `database_object` *get* defined? It would be easier to answer with a more complete version of `Loading_UI` and how it gets used – chepner Jan 15 '18 at 17:08
  • The database class is imported to 'Loading_UI' and then instantiated there. It's an object that contains information from the csv files. The actual code is not relevant here, since I only want to pass the object on to the main class. It may as well be e.g. a variable that is passed on. – El Fred Jan 15 '18 at 17:21
  • 1
    And that is trivial; you save the return value of what ever method returns the object, and pass that to `Main_UI`. Without seeing what `Loading_UI` looks like, though, we can't be any more specific. – chepner Jan 15 '18 at 17:50
  • 2
    This would be easier to answer if you provided a [mcve] – Bryan Oakley Jan 15 '18 at 18:04
  • I slimmed down the code in all 3 files with an easy, practical example. I hope this will help to get it solved! – El Fred Jan 15 '18 at 18:52

3 Answers3

0

The best way to do this might be to create a Main_UI object in Loading_UI file.

Loading_UI.py:

import Main_UI

# Create your progress bar
data = getDataFromCSV('file.csv')
# Delete your progress bar

main_ui = Main_Ui(data)
Gwendal Grelier
  • 526
  • 1
  • 7
  • 21
  • I may be missing the point here, but that seems similar to what I am doing above. I just need to be able to draw a new UI window as well. – El Fred Jan 15 '18 at 16:55
  • Why does the main window have to be created from Main_UI ? Can't you put your main window creation in the Loading_UI.py file ? – Gwendal Grelier Jan 15 '18 at 17:03
  • I'm trying to minimalise the code to make it easier to read and modify. – El Fred Jan 15 '18 at 17:23
  • I think this is the best approach. Just import your GUI load object, then when it's done simply destroy it. I don't think there will be an approach more readable & maintainable. – Nae Jan 16 '18 at 17:42
0

I'm no expert in tkinter but I've researched its documentation a little bit and this is how I'd do it.

Tkinter(as pygtk for that matter) has the concept of events and signals that are fired upon them. You can bind an event in any tkinter widget (such as a progressbar) using the bind function and have a callback function that will act on this. Apparently there's a predefined list of tkinter events that are available and in your case I think the <Destroy> A widget is being destroyed. will be of use.

So in your loading_ui.py file:

widget = ttk.Progressbar(parent, option=value, ...) # create your progressbar

#Bind it to the destroy event. Once destroyed call the proceed_with_main function and pass your object
widget.bind('<Destroy> ', lambda event, db=self.DataBase:
                         self.proceed_with_main(db)) 

def proceed_with_main(db): 
    from UI_Main import Main_UI

    Main = Main_UI(db)
    Main.main()
kingJulian
  • 5,601
  • 5
  • 17
  • 30
0

Ok multiple things are not done right here. Corrections are posted in the code directly.

(Run_loading.py)

from tkinter import *
from DataBase import DataBase

class Loading_UI:

    def __init__(self, master):

        self.master = master
        self.DataBase = DataBase("This is our object.")
        self.load_pct = DoubleVar()
        self.load_pct.set(0)
        loading_bar = Label(textvariable = self.load_pct)
        loading_bar.grid()

        self.handle_loading_progress()

    def handle_loading_progress(self):

        if self.load_pct.get() < 10:
            self.load_pct.set(self.load_pct.get() + 1)
            self.master.after(200, self.handle_loading_progress)
        else:
            self.show_main()

    def show_main(self):

        root.destroy()
        from UI_Main import Main_UI
        Main = Main_UI(self.DataBase)
        # Main.main() This line is wrong, your object Main_UI() does not have a defined 'main()' function

root = Tk()
root.geometry("100x100+300+300")
app = Loading_UI(root)
root.mainloop()

(UI_Main.py)

from tkinter import *

class Main_UI:

    def __init__(self, database_object):

        self.DataBase = database_object

        # Run this function to check that the 
        # data object is properly received.
        self.DataBase.show_content()
        self.tkWindow = Tk() # if you want to keep an new window you could keep this
        self.tkWindow.mainloop()

""" You shouldn't do things outside of the __init__() function of this class.
root = Tk()  lines to delete
app = Main_UI(root, database_object) lines to delete
root.mainloop() lines to delete """

""" This part is not necessary 
if __name__ == '__main__': 
    main() """
Gwendal Grelier
  • 526
  • 1
  • 7
  • 21