My title can look a little ambiguous, so here is an explanation.
Professional IDE like Pycharm
or Visual Studio Code
allow copying the folder, navigating to a specific directory and pasting it there. I would also like to implement that.
But in my case, shutil.copytree needs 2 arguments – source folder and destination folder.
So is there any way that one can copy a folder, navigate through the explorer, click paste or press ctrl+v
and the folder will be copied or pasted there, unlike shutil.copytree
where the user already need to provide the path?
Currently, I have a code that will copy the folder name to the clipboard.
import os import tkinter as tk import tkinter.ttk as ttk import clipboard class App(tk.Frame): def __init__(self, master, path): tk.Frame.__init__(self, master) self.tree = ttk.Treeview(self) ysb = ttk.Scrollbar(self, orient='vertical', command=self.tree.yview) xsb = ttk.Scrollbar(self, orient='horizontal', command=self.tree.xview) self.tree.configure(yscroll=ysb.set, xscroll=xsb.set) self.tree.heading('#0', text=path, anchor='w') abspath = os.path.abspath(path) root_node = self.tree.insert('', 'end', text=abspath, open=True) self.process_directory(root_node, abspath) self.tree.bind("<Control-c>",self.copy_to_clipboard) self.tree.grid(row=0, column=0) ysb.grid(row=0, column=1, sticky='ns') xsb.grid(row=1, column=0, sticky='ew') self.grid() def copy_to_clipboard(self,event,*args): item = self.tree.identify_row(event.y) clipboard.copy(self.tree.item(item,"text")) def process_directory(self, parent, path): try: for p in os.listdir(path): abspath = os.path.join(path, p) isdir = os.path.isdir(abspath) oid = self.tree.insert(parent, 'end', text=p, open=False) if isdir: self.process_directory(oid, abspath) except PermissionError: pass root = tk.Tk() path_to_my_project = 'C:\Users\91996\Documents' app = App(root, path=path_to_my_project) app.mainloop()
Advertisement
Answer
For windows, you can use the Powershell command Set-Clipboard
. To you can run the command use the subprocess module. Now that the file/folder is copied you can now paste it in file explorer using ctrl+v or using the right-click context menu.
To handle the paste simply use clipboard_get()
provided by tkinter which will provide you with the path to the file/folder. You can then make use of shutil.copy
/shutil.copytree
to copy the contents from src in your application.
You can then reload the tree view to make the changes visible.
Example:
import os import subprocess import shutil import tkinter as tk import tkinter.ttk as ttk class App(tk.Frame): def __init__(self, master, path): tk.Frame.__init__(self, master) self.tree = ttk.Treeview(self) ysb = ttk.Scrollbar(self, orient='vertical', command=self.tree.yview) xsb = ttk.Scrollbar(self, orient='horizontal', command=self.tree.xview) self.tree.configure(yscroll=ysb.set, xscroll=xsb.set) self.tree.heading('#0', text=path, anchor='w') self.abspath = os.path.abspath(path) self.tree.bind("<Control-c>",self.copy_to_clipboard) self.tree.bind("<Control-v>",self.create_directory_from_clipboard) self.tree.grid(row=0, column=0) ysb.grid(row=0, column=1, sticky='ns') xsb.grid(row=1, column=0, sticky='ew') self.grid() self.store_path = [] self.reload() def copy_to_clipboard(self,event,*args): item = self.tree.focus() self.store_path.append(self.tree.item(item,"text")) absolute_path = self.find_absolutePath(item) #cmd = r"ls '{}' | Set-Clipboard".format(absolute_path) # if you only want the contents of folder to be copied cmd = r"gi '{}' | Set-Clipboard".format(absolute_path) # copies both folder and its contents subprocess.run(["powershell", "-command", cmd], shell=True) # windows specific print("copied") def find_absolutePath(self, item): parent_id = self.tree.parent(item) if parent_id: parent = self.tree.item(parent_id, 'text') self.store_path.append(parent) return self.find_absolutePath(parent_id) else: absolute_path = os.path.join(*self.store_path[::-1]) self.store_path = [] return absolute_path def create_directory_from_clipboard(self, event): cur_item = self.tree.focus() self.store_path.append(self.tree.item(cur_item, "text")) dest = self.find_absolutePath(cur_item) src_path = self.clipboard_get() try: if os.path.isdir(src_path): src = os.path.basename(os.path.normpath(src_path)) #os.mkdir(os.path.join(src_path, src)) shutil.copytree(src_path, os.path.join(dest, src)) else: shutil.copy(src_path, dest) self.reload() print("pasted") except (FileExistsError, FileNotFoundError, shutil.SameFileError) as e: print(f"Error: {e}") def reload(self): self.tree.delete(*self.tree.get_children()) root = self.tree.insert('', 'end', text=self.abspath, open=True) self.process_directory(root, self.abspath) def process_directory(self, parent, path): try: for p in os.listdir(path): abspath = os.path.join(path, p) isdir = os.path.isdir(abspath) oid = self.tree.insert(parent, 'end', text=p, open=False) if isdir: self.process_directory(oid, abspath) except PermissionError: pass root = tk.Tk() path_to_my_project = r'mypath ' app = App(root, path=path_to_my_project) app.mainloop()
If you want this to work with other OS you will have to find the respective commands eg
alternatively, you can also make use of win32clipboard, 1 or you can make use of PyQt/pyslide’s QClipboard or PyGTK clipboard which provides convenient methods to do these kinds of operations