简体   繁体   中英

Use Tkinter in OOP approach

right now I know how to create a frame and ask for a directory path and file names using the code I found in stack overflow (Thanks to stack overflow). I need the path and file names (selected by user) somewhere else in my script. Here is the code:

import Tkinter, Tkconstants, tkFileDialog
class TkFileDialogExample(Tkinter.Frame):

  def __init__(self, root):
    Tkinter.Frame.__init__(self, root)

    # define buttons
    Tkinter.Button(self, text='askopenfilename', command=self.askopenfilename).pack()
    Tkinter.Button(self, text='askdirectory', command=self.askdirectory).pack()

  def askopenfilename(self):
    self.file = tkFileDialog.askopenfilename()

  def askdirectory(self):
    self.path = tkFileDialog.askdirectory()

if __name__=='__main__':
    root = Tkinter.Tk()
    TkFileDialogExample(root).pack()
    root.mainloop()
myFileDialog = TkFileDialogExample(root)
print myFileDialog.file

But what I do not know, is how to use the path and file names outside of the class? This way I got this error:

 Traceback (most recent call last):
  File "C:\Users\xxx .py", line 24, in <module>
    myFileDialog = TkFileDialogExample(root)
  File "C:\Users\xxx.py", line 5, in __init__
    Tkinter.Frame.__init__(self, root)
  File "C:\Python27\ArcGIS10.1\lib\lib-tk\Tkinter.py", line 2453, in __init__
    Widget.__init__(self, master, 'frame', cnf, {}, extra)
  File "C:\Python27\ArcGIS10.1\lib\lib-tk\Tkinter.py", line 1974, in __init__
    (widgetName, self._w) + extra + self._options(cnf))
TclError: can't invoke "frame" command:  application has been destroyed

Thank you in advance.

A quick and dirty way could be to use a global variable that is defined in the main body of the script and then it is set during the mainloop . In this case I used a dictionary to store in a single variable all the data you need.

import Tkinter, Tkconstants, tkFileDialog
class TkFileDialogExample(Tkinter.Frame):

  def __init__(self, root):
    Tkinter.Frame.__init__(self, root)

    # define buttons
    Tkinter.Button(self, text='askopenfilename',
                   command=self.askopenfilename).pack()
    Tkinter.Button(self, text='askdirectory',
                   command=self.askdirectory).pack()

    self.file = '' # initialize attributes as empty strings
    self.path = '' #

    global outputValues

  def askopenfilename(self):
    self.file = tkFileDialog.askopenfilename() # set attribute
    outputValues['file'] = self.file           # set element of global variable
    print self.file

  def askdirectory(self):
    self.path = tkFileDialog.askdirectory()    # set attribute
    outputValues['path'] = self.path           # set element of global variable
    print self.path

if __name__=='__main__':
    root = Tkinter.Tk()
    TkFileDialogExample(root).pack()
    myFileDialog = TkFileDialogExample(root)
    outputValues = {}                          # define global variable
    myPath = myFileDialog.path
    root.mainloop()
    for key, val in outputValues.iteritems():  # the mainloop is over, but
        print key, val                         # the data you set is still
                                               # available

The downside is that usually global variables "pollute" the namespace making it hard to track down bugs, so they are often frowned upon. Maybe some other user can provide a better way.

First Version

I would suggest that you initialize (to empty strings) the attributes path and file in the __init__ method and set them to the user input's value when pressing the buttons.

import Tkinter, Tkconstants, tkFileDialog
class TkFileDialogExample(Tkinter.Frame):

  def __init__(self, root):
    Tkinter.Frame.__init__(self, root)

    # define buttons
    Tkinter.Button(self, text='askopenfilename',
                   command=self.askopenfilename).pack()
    Tkinter.Button(self, text='askdirectory',
                   command=self.askdirectory).pack()

    self.file = '' # initialize attributes as empty strings
    self.path = '' #

  def askopenfilename(self):
    self.file = tkFileDialog.askopenfilename() # set attribute
    print self.file

  def askdirectory(self):
    self.path = tkFileDialog.askdirectory()    # set attribute
    print self.path

if __name__=='__main__':
    root = Tkinter.Tk()
    TkFileDialogExample(root).pack()         # these lines must be *before*
    myFileDialog = TkFileDialogExample(root) # root.mainloop()
    root.mainloop()

About the error you get, the important part is:

TclError: can't invoke "frame" command:  application has been destroyed

which tells you that once you close the window (that is, you exit the mainloop of the root object) you cannot reference root anymore and so you cannot attach another child ( myFileDialog = TkFileDialogExample(root) ) to it.
Just move those two lines before root.mainloop , that is, where the object still exists.

To use the file name outsidee the class just save it as an attribute then call instace to get it:

#Here we are outside the class

if __name__=='__main__':
   root = Tkinter.Tk()
   myFileDialog = TkFileDialogExample(root)
   myFileDialog.pack()
   print myFileDialog.file
   root.mainloop()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM