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