Andrew Louis
Andrew Louis

Reputation: 303

Tkinter store filename through menubar button

I have created functions that can display graphs and tables of csv files in a GUI I am making with tkinter.

I have a menubar with an import button, a plot button, and a table button. The plot and table button can successfully plot graphs and tables of csv files respectively.

What I'd like to do, is when the user selects the import button, they select a file of their choice. Then, if they happen to select the plot button, the plot function works on the file they chose from import. Moreover, if they happen to select the table button, the table function works on the file they chose from import.

I have created a file opening function called openfile() which remembers the name of the file opened.

The problem is that I don't know how to use menubar and openfile() such when the import button is clicked, my application stores the filename.

Any tips on how I would go about doing this?

Here's the code I've written for the menubar and openfile():

def openfile():
    name= askopenfilename() 
    return (name[19:])

class MyApp(tk.Tk):

    def __init__(self, *args, **kwargs):

        tk.Tk.__init__(self, *args, **kwargs)

        tk.Tk.wm_title(self, "MyApp")
        # main frame
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand = True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand = True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        # creates the menubar at the top of the window
        menubar = tk.Menu(container)

        # import menu for importing csv files, initializes a file opening function (tbd)
        filemenu = tk.Menu(menubar, tearoff=0)
        filemenu.add_command(label="Import a CSV File", command = file_openerfunction)
        menubar.add_cascade(label= "Import", menu=filemenu)

        # plot menu for creating graphs and figures
        Plot = tk.Menu(menubar, tearoff =0 )
        Plot.add_command(label="Plot My CSV File", command= popupgraph)
        menubar.add_cascade(label="Plot", menu=Plot)

        # table menu for viewing data in a table
        table = tk.Menu(menubar, tearoff = 0)
        table.add_command(label="View MY CSV File", command = table)
        table.add_cascade(label = "View Data", menu = table)

        tk.Tk.config(self, menu=table)
        ....
        ....

Upvotes: 0

Views: 1212

Answers (3)

otorrillas
otorrillas

Reputation: 4783

First of all, I would suggest you take an Object Oriented approach to split each component behaviour.

This way, you would have a class App, where you would initialise the main components of the app:

class App(tk.Tk):

    def __init__(self,parent):
        Tk.__init__(self,parent)
        self.parent = parent
        self.initialize()

    def initialize(self):
        ...

        ...
        # Menubar
        self.menubar = MyMenuBar(self)

        # Filemenu
        self.filemenu = MyFileMenu(self, menubar)

        # Plot
        self.plot = MyPlot(self, menubar)

        # The rest for all the other components
        ...

    def get_import_filename(self):
        # Ask the child for the filename and return it
        return self.filemenu.get_filename()

And then define every of your objects:

class MyPlot(tk.Menu):
      def __init__(self, parent, menubar):
           tk.Menu.__init__(self, menubar, tearoff=0)
           self.parent = parent
           self.initialize()

      def initialize(self):
          self.add_command(label="Plot My CSV File", command= self.popupgraph)  

      def popupgraph(self):
          # Ask the parent for the filename
          filename = self.parent.get_import_filename()
          # Do whatever with the filename...like open a file

class MyFileMenu(tk.Menu):
      def __init__(self, parent, menubar):
           tk.Menu.__init__(self, menubar, tearoff=0)
           self.parent = parent
           self.initialize()
      def initialize(self):
          self.add_command(label="Import a CSV File", command = file_opener)
      def file_opener(self):
          # Your file opener function goes here
          ...
          # At the end, save the imported file:
          self.filename = filename
      def get_filename(self):
          return self.filename

Finally, have the main to run it:

def main():
    app = App(None)
    app.title('Auto login')
    app.mainloop()

if __name__ == "__main__":
    main()

Upvotes: 1

martineau
martineau

Reputation: 123501

I don't understand the way you were trying to do some things (or why you were doing them at all in some cases), but here's a runnable example that creates a simple Choices cascading menu in the upper-left corner of the window of simple tkinter app. Hopefully you';; be able to adapt and integrate it into your project's code.

I made The command for importing CSV files, file_openerfunction, a class method and have it call the openfile() function because that way the returned value (the filename) can be store as an attribute in self.filename. This will allow it to used in the other command choices after it is create (so they will know what file to operate upon).

try:
    import Tkinter as tk
    from tkFileDialog import askopenfilename
except ModuleNotFoundError:   $ Python 3
    import tkinter as tk
    from tkinter.filedialog import askopenfilename

def openfile():
    name = askopenfilename()
    return name[19:]

class MyApp(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self, master)
        self.master.title("MyApp")

        self.pack(side="top", fill="both", expand=True)
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)

        top = self.winfo_toplevel()
        self.menubar = tk.Menu(top)
        top['menu'] = self.menubar

        self.submenu = tk.Menu(self.menubar)
        self.menubar.add_cascade(label='Choices', menu=self.submenu)

        self.submenu.add_command(label="Import a CSV File",
                                 command=self.file_openerfunction)
        self.submenu.add_command(label="Plot My CSV File",
                                 command=self.popupgraph)
        self.submenu.add_command(label="View MY CSV File",
                                 command=self.table)

    def file_openerfunction(self):
        self.filename = openfile()

    def popupgraph(self): pass
    def table(self): pass

app = MyApp()
app.mainloop()

I also suggest you read and follow the PEP 8 - Style Guide for Python Code which will help standardize the code your write and improve its readability.

Upvotes: 0

Andrew Louis
Andrew Louis

Reputation: 303

otorrillas solution worked perfectly.

I found another simple way to resolve this issue. In order for the GUI to remember the file selected from import, have the file name be appended to a list. Then, call on popupgraph() and viewcsv() on the list element. Here's the new code for my file opening function.

file_list = []

def openfile():
    name= askopenfilename() 
    file_list.append(name[19:])

Upvotes: 0

Related Questions