Skip to content
Advertisement

How to copy, cut folder from one folder to another using ctrl+c and ctrl+v

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

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement