Python Tkinter: Passing List Arguments to Populate

2019-08-05 18:02发布

Summary I am building a Tkinter program in Python 2.7. The goal is to automatically populate a list with available removable flash drives. When the user selects a drive or multiple drives from the list, the selected drive(s)(sel_drv) is passed to another function which will search the drive for a specific file type and generate a list to populated on the screen.

The Problem The issue I am running into is the ordering of the functions. When the user selects a drive its passed the drv_sel variable which is then appended to the sel_drives list. I keep getting errors for trying to use the sel_drv before its defined, or TypeErrors.

Important modules: drive_ctypes.find_rmdrv() - This function will search the computer for removable drives and populate the list. (This is working fine)

file_search.file_search(sel_drives) - This function will search the drives(sel_drives) and return a list of all files of a certain type. (This function works, but I can't pass sel_drive properly.

Background I am new to programming and Python, including class and OOP. I would appreciate any resources that might help me learn more about Tkinter and Classes/OOP.

Here is the error

Traceback (most recent call last):
  File "C:\Python27\window.py", line 70, in <module>
    main()
  File "C:\Python27\window.py", line 64, in main
    ex = Example(root)
  File "C:\Python27\window.py", line 13, in __init__
    self.initUI()
  File "C:\Python27\window.py", line 33, in initUI
    for i in sel_files:
TypeError: 'instancemethod' object is not iterable

Here is the code:

from Tkinter import *
import drive_ctypes
import file_search

#global sel_files
#sel_files[]

class Example(Frame):

    def __init__(self, parent):
        Frame.__init__(self, parent)   
        self.parent = parent        
        self.initUI()

    def initUI(self):      
        self.parent.title("Listbox") 
        self.pack(fill=BOTH, expand=1)

    ## Drive Select List Box
        global rdrive
        rdrive = drive_ctypes.find_rmdrv()
        lb = Listbox(self, height=10, selectmode=MULTIPLE)
        for i in rdrive:
            lb.insert(END, i)

        lb.bind("<<ListboxSelect>>", self.onSelect)
        sel_files = self.onSelect

        lb.grid(row =3, column =2)

    ## File Select List Box
        flb = Listbox(self, height=10, selectmode=MULTIPLE)    
        for i in sel_files:
            flb.insert(END, i)            
        flb.grid(row =3, column =4) 


    def onSelect(self, val):
        sender = val.widget
        drv_sel = sender.curselection()
        print drv_sel
        ## List of Drives Selected
        sel_drives = []
        for i in drv_sel:
            drive_with_gb = rdrive[i]
            ## This trims the name of the drive for the file_search function
            drive = drive_with_gb[:-9]
            ## This is creating a list to pass to the file_search function
            sel_drives.append(drive)
        sel_files = file_search.file_search(sel_drives)
        return sel_files



    def findfiles(self,val):
        sender = val.widget




def main():

Any Assistance is GREATLY appreciated!

1条回答
劫难
2楼-- · 2019-08-05 18:38

I amended your example, and made dummy rdrive and sel_files variables. Otherwise I can't reproduce your problem. Have a look at this:

from Tkinter import *



# dummy list so that the code does not relay on actually drives and files
rdrive = ['drive1','drive2','drive3']

sel_files = {'drive1': ['file1','file2'],
                  'drive2': ['file3','file4'],
                  'drive3': ['file6','file5']}

class Example(Frame):

    def __init__(self, parent):
        Frame.__init__(self, parent)
        self.parent = parent
        self.initUI()

    def initUI(self):
        self.parent.title("Listbox")
        self.pack(fill=BOTH, expand=1)

        # Drive Select List Box
        # global rdrive
        # rdrive = drive_ctypes.find_rmdrv()            

        # use dummy rdrive instead of physical drives. Otherwise,
        # cant reproduce the problem.  

        self.lb = Listbox(self, height=10, selectmode=MULTIPLE)
        for i in rdrive:
            self.lb.insert(END, i)

        self.lb.bind("<<ListboxSelect>>", self.onSelect)



        self.lb.grid(row =3, column =2)

        ## File Select List Box
        self.flb = Listbox(self, height=10, selectmode=MULTIPLE)

        self.flb.grid(row =3, column =4)


    def onSelect(self, event):
        # most changes are here. GUI programming is event driven, so you need
        # to get the list of files for selected drive (i.e. when selection even occurs).
        # Also here you respond the the even, so that the right list is populated.


        # get widget (i.e. right listbox) and currently selected item(s) 
        widget = event.widget
        selection=widget.curselection()

        files_avalibe = []

        # if something was selected, than get drives for which it was selected
        # and retrieve files for each drive
        if selection:


            for drive_i in selection:
                selected_drive = rdrive[drive_i]
                files_avalibe += sel_files[selected_drive]


            print(files_avalibe)

        # once we have files from the selected drive, list them 
        # in the right list box 
        self.update_file_list(files_avalibe)



    def update_file_list(self, file_list):
          # updates right listbox
          self.flb.delete(0, END)
          for i in file_list:
            self.flb.insert(END, i)




    def findfiles(self,val):
        sender = val.widget




root = Tk()
f = Example(root)
root.mainloop()

How it works is shown here:

enter image description here

Sorry for not detailed explanation what was changed. But I think you can figure these things yourself. The main problem with your code was sel_files = self.onSelect. This just assigns a function to sel_files, not it output. To get the actual file list for a selected drive, need to do it in onSelect.

查看更多
登录 后发表回答