1

I've tried a number of different things and searched for the topic here, but I can't find a solution to this. The code runs fine, but when I try to paste what it's copied to the clipboard, the program I'm pasting into stops responding. As soon as I close my Python application, the programs start to respond again, but the clipboard is empty. This is for a school assignment and it requires me to use only tools that come with the Python installation, so no Pyperclip or the like.

Here's the code I'm working from:

from tkinter import Tk
r = Tk()
r.withdraw()
r.clipboard_clear()
r.clipboard_append('This is a test to try to copy to clipboard')
r.update()
r.destroy()
Justin Meshew
  • 31
  • 1
  • 3
  • Use `r.mainloop()` instead of `r.destroy()`. – Novel Aug 19 '18 at 20:09
  • That works, but it doesn't allow the program to continue afterward. The full program is a calculator, this is just the snippet related to the clipboard. – Justin Meshew Aug 19 '18 at 20:20
  • You'll need to show us the full program if you want help with that then. If the program contains tkinter code then you can simply use `r.clipboard_clear()` and `r.clipboard_append()` and forget the rest. – Novel Aug 19 '18 at 23:42
  • 1
    You cannot do this. Tkinter needs to stay active for the clipboard to keep the content. If you close the instance in the same loop as you are appending to clipboard you will just end up losing whats in the clipboard. At least this is the behavior with Tkinters built in methods. You may be able to get a clipboard library that does not have this problem. – Mike - SMT Aug 20 '18 at 14:29

4 Answers4

2

You cannot do this with tkinters built in clipboard method. Tkinter needs to stay active for the clipboard to keep the content. If you close the instance in the same loop as you are appending to clipboard you will just end up losing whats in the clipboard. At least this is the behavior with Tkinters built in methods.

You could pip install clipboard and use its methods. This will keep the content on the clipboard even after Tkinter closes.

from tkinter import Tk
import clipboard as cb


r = Tk()
r.withdraw()
cb.copy('This is a test to try to copy to clipboard')
r.destroy()
Mike - SMT
  • 14,784
  • 4
  • 35
  • 79
  • Does this require the user to install any software like Pyperclip? The instructions on the assignment this is about are: "Solutions that require the user install any software will NOT be accepted (in case you are not sure, this means NO Pyperclip.)" – Justin Meshew Aug 20 '18 at 22:06
  • The user needs to install python yes? If you are going to build a stand alone executable you could use something like freeze to get that done. That said I do not think that Tkinter can keep data on the clipboard if you destroy the root window. You will have to keep the Tkinter application going if you wish to keep the data in the clipboard using Tkinters build in methods. – Mike - SMT Aug 20 '18 at 22:40
2

I use os.system to pipe the text to the clip command.

I was worried this would be insecure at first because a user could input a shell command as the text to be copied into the clipboard, but I realized since this is a calculator program it should have input validation to not accept any non-numerical input anyway so that solves that problem.

def clipboard(text):
    cmd = 'echo | set /p nul=' + str(text) + '| clip'
    os.system(cmd)
Cristian Ciupitu
  • 20,270
  • 7
  • 50
  • 76
Justin Meshew
  • 31
  • 1
  • 3
  • Is there a way to make it safer? Also I don't think it works on Linux – TheLizzard Mar 26 '21 at 12:35
  • @TheLizzard yeah, use [`subprocess.run`](https://docs.python.org/3/library/subprocess.html#subprocess.run) to send the text to the **clip** command, i.e. `subprocess.run("clip", input=text.encode("ascii"))` . If the text has non-ASCII characters, `subprocess.run("clip", input=text.encode("utf_16_le"))` seems to work (encoding chosen based on answers to this [question](https://stackoverflow.com/q/13499920)). – Cristian Ciupitu May 25 '22 at 15:02
  • @TheLizzard on X11 systems, e.g. Linux, FreeBSD, NetBSD, OpenBSD, you can use the [**xclip**](https://github.com/astrand/xclip) program instead of clip, but it's not preinstalled most of the time. Also Linux software prefers the UTF-8 encoding. – Cristian Ciupitu May 25 '22 at 15:07
-1

Try using pyperclip e.g.

import pyperclip 
pyperclip.copy(“hello”)
#copies hello into the clipboard 

Check out the official pyperclip documentation at https://pyperclip.readthedocs.io/en/latest/introduction.html

MJCS
  • 31
  • 1
  • 6
  • Unfortunately, this is not an option for me. The instructions on the assignment this is about are: "Solutions that require the user install any software will NOT be accepted (in case you are not sure, this means NO Pyperclip.)" – Justin Meshew Aug 20 '18 at 22:07
  • Sorry that this couldn’t help you @Justin Meshew but this should help others with the same problem – MJCS Aug 21 '18 at 09:23
-1
class main ( ):
    def __init__(self, parent): 
        #super ( ).__init__()

        self.menu = tk.Menu ( parent, tearoff = 0, 
                      postcommand = self.enable_selection )
        self.menu.add_command ( label = 'Cut', command = self.cut_text )
        self.menu.add_command ( label = 'Copy', command = self.copy_text )      
        self.menu.add_command ( label = 'Paste', command = self.paste_text )        
        self.menu.add_command ( label = 'Delete', command = self.delete_text )      
        self.text = tk.Text ( height = 10, width = 50 )
        self.text.bind ( '<Button-3>', self.show_popup )
        self.text.pack ()


        mainloop ()

    def enable_selection ( self ):
        self.state_clipboard = tk.ACTIVE
        if self.text.tag_ranges (tk.SEL):
            self.state_selection = tk.ACTIVE 
        else: 
            self.state_selection = tk.DISABLED

        try:
            self.text.selection_get ()

        except tk.TclError as e:
            pass
            #print ( e )
            #self.state_clipboard = tk.DISABLED
            #self.menu.entryconfig ( 0, state = self.state_selection )
            #self.menu.entryconfig ( 1, state = self.state_selection )
            #self.menu.entryconfig ( 2, state = self.state_clipboard )
            #self.menu.entryconfig ( 3, state = self.state_selection )

    def cut_text ( self ):
        self.copy_text ()
        self.delete_text ()

    def copy_text ( self ):
        selection = self.text.tag_ranges ( tk.SEL )
        if selection:
            self.text.clipboard_clear ()
            self.text.clipboard_append ( self.text.get (*selection) )

    def paste_text ( self ):
        try:
            self.text.insert ( tk.INSERT, self.text.clipboard_get () )
        except tk.TclError:
            pass

    def delete_text ( self ):
        selection = self.text.tag_ranges ( tk.SEL )
        if selection:
            self.text.delete ( *selection )

    def show_popup ( self, event ):
        self.menu.post ( event.x_root, event.y_root )

if __name__ == '__main__':
    app = main ( tk.Tk() )
Melon
  • 604
  • 1
  • 7
  • 30