How to get the route of selected file using filedialog.askopenfilename() from another method in TkInter Python 3

I've just started working with GUIs in python 3 using TKInter, and I simply want to open a file, read it and write some columns of it on another excel file, so I created a method for asking the route of the file that I want to read:

def UploadAction(event=None):
    filename = filedialog.askopenfilename()
    print('Selected: ', filename)


lblOriginFile = Label(window, text='Select origin file: ')
btnOriginFile = Button(window, text='Origin file: ', command=UploadAction())

But after that I want to use

fileToRead = pandas.read_excel(<FILENAME>)

But I don't know how to access the value 'filename' from outside of the UploadAction method.

Thank you very much!

Upvotes: 1

Views: 469

Answers (1)

Joel Toutloff
Joel Toutloff

Reputation: 484

There are a few ways of doing this.

The simplest way is to add a single line:

def UploadAction(event=None):
    global filename
    filename = filedialog.askopenfilename()
    print('Selected: ', filename)


lblOriginFile = Label(window, text='Select origin file: ')
btnOriginFile = Button(window, text='Origin file: ', command=UploadAction())

that "global filename" will make it so when 'filename' is used in the function, it refers to a global variable which you will be able to access where ever.

There are a lot of people who frown on using global variables like that though. If you ever use the variable name 'filename' later on and don't want it to be global, it can be very tricky to keep track of what is what. So it basically limits you from using 'filename' anywhere else without causing some serious confusion.

An alternative would be to come up with some data structure that you use to hold information that you later use. A common way of doing this would be to have a dictionary with a name you only ever use globally so there is never any confusion and then put the information in that dictionary. Example:

my_global_dictionary = {}

def UploadAction(event=None):
    global my_global_dictionary
    my_global_dictionary['filename'] = filedialog.askopenfilename()
    print('Selected: ', filename)


lblOriginFile = Label(window, text='Select origin file: ')
btnOriginFile = Button(window, text='Origin file: ', command=UploadAction())

And now, whenever you want that file information you can call upon the dictionary. This is a bit more work and a bit more ugly, but making it clear that it is used for global purposes makes it much easier to keep track of what variables are where. There is another advantage of this, and that is that everything you store as a variable remains in memory until it has no variable name attached to it any more. Making a global variable basically means that that bit in the memory will always have a name, and it will never get cleaned up until the program ends. This is totally okay for little things or things that really need to be there all the time, but if you are using a lot of global variables, you are very much making a mess of the memory until the program ends. Having all such variables wrapped up into on dictionary makes it much easier for you to remove them when you are done with them by using pop or by clearing the dictionary.

What I often do is make a class that is really just for holding those sorts of things.

class Globals:
    filename = None

def UploadAction(event=None):
    Globals.filename = filedialog.askopenfilename()
    print('Selected: ', filename)


lblOriginFile = Label(window, text='Select origin file: ')
btnOriginFile = Button(window, text='Origin file: ', command=UploadAction())

I think it looks a lot prettier and is more understandable. This is slower than dictionaries though. Dictionary lookups are quite fast while dot lookups are kinda slow so if you are using one of these variables in a nested for-loop or calling it every frame, it will slow down a lot easier than the dictionary method.

Upvotes: 3

Related Questions