Search code examples
pythontkinteroperating-systemdropdownopenfiledialog

Dropdown files list dependent from another dropdown folder list


I need help on how to do dependent dropdown files list from another dropdown folder list. In one folder, I have 5 List of folder, then for each folder, I have 5 list of files. In my code, I already make 2 dropdown function which is 1st dropdown : list out all the folder . 2nd dropdown : I want make a dependent list in 2nd dropdown which is depend on the folder that I have select in 1st dropdown. is that possible?

For example:

Directory : 'C:\Users\TestFile'

folder List : -folder1 -folder2 -folder3 -folder4 -folder5

file list in each folder: folder1 : apple1,apple2,apple3,..... folder2 : orange1,orange2,orange3,..... folder3 : grape1,grape2,grape3,..... folder4 : lych1,lych2,lych3,..... folder5 : strwberry1,strwberry2,strwberry3,.....

So if i select folder1 in my first dropdown, I want all files (apple1,apple2,apple3,..... )that in folder1 listed out in 2nd dropdown.

Here is my code

from tkinter import *
from functools import partial
import os
import tkinter as tk
from tkinter import ttk
#import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import pandas as pd
import webbrowser
from webbrowser import open as openlink
import urllib

def open(file_menu):
    filename = file_menu.get()

    open_in_browser_link = f"file://{os.path.join(folder, filename)}"
    print(open_in_browser_link)

    webbrowser.open(open_in_browser_link)



def clear_data():
#    tv1.delete(*tv1.get_children())
    return None



folder = os.path.realpath(r'C:\Users\TestFile')
filelist = [fname for fname in os.listdir(folder)]

master = tk.Tk()
master.geometry('1200x800')
master.title('THB')

# Frame for TreeView
frame0 = tk.LabelFrame(master, text="Chapter",background="light grey")
frame0.place(height=500, width=1200, rely=0.0, relx=0.0)

optmenu = ttk.Combobox(frame0, values=filelist, state='readonly')
optmenu.pack()
optmenu.set("Chapter")

optmenu1 = ttk.Combobox(frame0, values=????, state='readonly')
optmenu1.pack()
optmenu1.set("SubChapter")

button_select = tk.Button(frame0, text="Show Data",
                          width=15,
                          height=2,
                          compound=tk.CENTER,
                          command=partial(open, optmenu1))

button_select.place(relx=0.5, rely=0.5)
button_select.pack(side=tk.TOP)


master.mainloop()

Solution

  • The basic algorithm behind the code want can be split as follows:

    • bind each option select signal of the first combobox to a function,
    • that scans a directory and sets the available files to the second combobox.

    Now, the important part for this operation is:

    optmenu.bind("<<ComboboxSelected>>", onSelect)
    
    ...
    ...
    
    def onSelect(event):
        folder_name = filelist[event.widget.current()]
        folder_path = os.path.join(folder, folder_name)
    
        print(f"folder selected:{folder_name}, folder_path:{folder_path}, index:{event.widget.current()}")
    
        global sub_files
        sub_files = []
        for f_name in os.listdir(folder_path):
            sub_files.append(f_name)
        print(sub_files)
    
        optmenu1['values'] = sub_files  # set sub directories to combobox
    

    The complete code:

    from tkinter import *
    from functools import partial
    import os
    import tkinter as tk
    from tkinter import ttk
    # import tkinter as tk
    from tkinter import filedialog, messagebox, ttk
    import pandas as pd
    import webbrowser
    from webbrowser import open as openlink
    import urllib
    
    
    def open(file_menu):
        filename = file_menu.get()
    
        open_in_browser_link = f"file://{os.path.join(folder, filename)}"
        print(open_in_browser_link)
    
        webbrowser.open(open_in_browser_link)
    
    
    def clear_data():
        #    tv1.delete(*tv1.get_children())
        return None
    
    
    def onSelect(event):
        folder_name = filelist[event.widget.current()]
        folder_path = os.path.join(folder, folder_name)
    
        print(f"folder selected:{folder_name}, folder_path:{folder_path}, index:{event.widget.current()}")
    
        global sub_files
        sub_files = []
        for f_name in os.listdir(folder_path):
            sub_files.append(f_name)
        print(sub_files)
    
        optmenu1['values'] = sub_files  # set sub directories to combobox
    
    
    folder = os.path.realpath(r'C:\Users\TestFile')
    sub_files = []
    # folder = os.path.realpath(r'./testing')
    filelist = [fname for fname in os.listdir(folder)]
    
    master = tk.Tk()
    master.geometry('1200x800')
    master.title('THB')
    
    # Frame for TreeView
    frame0 = tk.LabelFrame(master, text="Chapter", background="light grey")
    frame0.place(height=500, width=1200, rely=0.0, relx=0.0)
    
    optmenu = ttk.Combobox(frame0, values=filelist, state='readonly')
    optmenu.pack()
    optmenu.set("Chapter")
    optmenu.bind("<<ComboboxSelected>>", onSelect)
    
    optmenu1 = ttk.Combobox(frame0, values=[], state='readonly')
    optmenu1.pack()
    optmenu1.set("SubChapter")
    
    button_select = tk.Button(frame0, text="Show Data",
                              width=15,
                              height=2,
                              compound=tk.CENTER,
                              command=partial(open, optmenu1))
    
    button_select.place(relx=0.5, rely=0.5)
    button_select.pack(side=tk.TOP)
    
    master.mainloop()
    
    

    Now, this code, opens the C:\Users\TestFile folder, and scans each direcotry and sets to first combobox (optmenu).

    Then, when you select any one option in optmenu, it calls the onSelect() function. This onSelect function, read all files available inside the folder selected in optmenu, and shows the available files in optmenu1.