简体   繁体   中英

How to get askopenfilenames to loop over a user input?

I've just started learning Python and I'm trying to achieve this in tkinter :

  • Get user to select any multiple number of files in any directory locations and store it in another folder

I'm not sure if there's any other more efficient ways of doing this but I've tried solving this by:

  • Getting the user to input how many files they are searching for (I set 2 as default)
  • loop over the number of files and ask for the user to select the files
  • send all the files to the new location

The problem is I can't quite get the storing the files and looping to work well. Here's the code:

import tkinter as tk
from tkinter import filedialog, ttk
import shutil


class Getfiles():
    def __init__(self):
        #  initialising the screen name, size title and icon
        root = tk.Tk()
        root.geometry('450x100')
        root.resizable(0, 0)
        root.configure(bg='#002060')

        # initialising integer value to pass to select_files method
        self.var = tk.IntVar()
        self.var.set('2')

        # Initialising the frame to insert our widget
        frame_three = tk.Frame(root, bg='#002060')
        frame_three.pack(side='top', fill='both')

        # setting label to tell user to input no. of files
        num_label = ttk.Label(frame_three, text='No. of files: ', background='#002060', foreground='white')
        num_label.pack(side='left', padx=(40, 10), pady=(20, 20))

        # setting number of files user wants to fetch
        files_num = ttk.Entry(frame_three, width=3, textvariable=self.var)
        files_num.pack(side='left', padx=(10, 40), pady=20)

        # get user to select the files listed
        select_button = ttk.Button(frame_three, text='Select files', width=30, command=self.select_files)
        select_button.pack(side='left', padx=(50, 10))

        root.mainloop()


    def select_files(self):
        file_list = []
        for i in range(self.var.get()):
            file_chosen = filedialog.askopenfilenames(title='Choose a file')
            file_list = list(file_chosen)
            list += file_list
        self.copy(file_list)

    def copy(self, file_list):
        destination = filedialog.askdirectory()
        for file in file_list:
            shutil.copy(file, destination)


if __name__ == '__main__':
    Getfiles()

Solution1 (as per your needs - when files can be in different locations)

Things to note: I changed filedialog.askopenfilenames() to filedialog.askopenfilename() because if the user is supposed to copy exact number of files overall (defined by user input in self.var ), in that case, allowing the user to select more than one file at a time may result in exceeding the value of self.var because our for loop will always run self.var.get() times , and if user selects two(say) files on each iteration , he will end up copying 2*self.var.get() files in total, and your idea of asking for the exact number of files to copy in the start will not do any good for us.

Your code was not working because you were setting the file_list variable to a new value list(files_chosen) on every iteration (instead of appending it to the list)

import tkinter as tk
from tkinter import filedialog, ttk
import shutil


class Getfiles():
    def __init__(self):
        #  initialising the screen name, size title and icon
        root = tk.Tk()
        root.geometry('450x100')
        root.resizable(0, 0)
        root.configure(bg='#002060')

        # initialising integer value to pass to select_files method
        self.var = tk.IntVar()
        self.var.set('2')

        # Initialising the frame to insert our widget
        frame_three = tk.Frame(root, bg='#002060')
        frame_three.pack(side='top', fill='both')

        # setting label to tell user to input no. of files
        num_label = ttk.Label(frame_three, text='No. of files: ', background='#002060', foreground='white')
        num_label.pack(side='left', padx=(40, 10), pady=(20, 20))

        # setting number of files user wants to fetch
        files_num = ttk.Entry(frame_three, width=3, textvariable=self.var)
        files_num.pack(side='left', padx=(10, 40), pady=20)

        # get user to select the files listed
        select_button = ttk.Button(frame_three, text='Select files', width=30, command=self.select_files)
        select_button.pack(side='left', padx=(50, 10))

        root.mainloop()


    def select_files(self):
        files_list = []
        
        for x in range(self.var.get()):
            files_chosen = filedialog.askopenfilename(title='Choose a file')
            files_list += list(files_chosen)

        self.copy(files_list)

    def copy(self, file_list):
        destination = filedialog.askdirectory()
        for file in file_list:
            shutil.copy(file, destination)


if __name__ == '__main__':
    Getfiles()

solution2 (can select multiple files - all in same directory)

This is recommended and you will see this approach being used in almost every application. Here You don't need to ask the user about how many files do they wish to copy. They can select anywhere from a single file to 1000 files (if present & required),but files will be supposed to be in same directory . For files of other directories they can click on select files button again, follow the process.

Note that I did not remove the label and entry box for entering the number of files, but consider them ignored from the GUI.

import tkinter as tk
from tkinter import filedialog, ttk
import shutil


class Getfiles():
    def __init__(self):
        #  initialising the screen name, size title and icon
        root = tk.Tk()
        root.geometry('450x100')
        root.resizable(0, 0)
        root.configure(bg='#002060')

        # initialising integer value to pass to select_files method
        self.var = tk.IntVar()
        self.var.set('2')

        # Initialising the frame to insert our widget
        frame_three = tk.Frame(root, bg='#002060')
        frame_three.pack(side='top', fill='both')

        # setting label to tell user to input no. of files
        num_label = ttk.Label(frame_three, text='No. of files: ', background='#002060', foreground='white')
        num_label.pack(side='left', padx=(40, 10), pady=(20, 20))

        # setting number of files user wants to fetch
        files_num = ttk.Entry(frame_three, width=3, textvariable=self.var)
        files_num.pack(side='left', padx=(10, 40), pady=20)

        # get user to select the files listed
        select_button = ttk.Button(frame_three, text='Select files', width=30, command=self.select_files)
        select_button.pack(side='left', padx=(50, 10))

        root.mainloop()


    def select_files(self):
        files_list = []

        files_chosen = filedialog.askopenfilenames(title='Choose a file')

        self.copy(list(files_chosen))

    def copy(self, file_list):
        destination = filedialog.askdirectory()
        for file in file_list:
            shutil.copy(file, destination)


if __name__ == '__main__':
    Getfiles()

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