'strange things happening with Tkinter clipboard

UPDATE: After some more troubleshooting, I think the problem is that I am calling tk's get clipboard method from within the mainloop method of the Tk app. I will experiment with using the tk.Tk.after method to avert this problem. I will add lines in my code flagged with a comment to reflect this change. I will report back here if this solves the problem.

General Description: Using pyautogui to select, then copy text, if I try to access the clipboard contents with tk.clipboard_get() within the function (after copying to clipboard) I will sometimes get the exception shown below. However afterwards, I check the clipboard again, either by again calling app.clipboard_get() in the terminal, or by 'ctrl' + 'v', and I can access the clipboard content without raising the exception, and it is not empty or missing.

Here is the exception

line 26, in highlight_then_copy_then_print
    clipboardText = self.clipboard_get()
  File "C:\Users\XisUnknown\AppData\Local\Programs\Python\Python36-32\lib\tkinter\__init__.py", line 801, in clipboard_get
    return self.tk.call(('clipboard', 'get') + self._options(kw))
_tkinter.TclError: CLIPBOARD selection doesn't exist or form "STRING" not defined

Here is the sample code...

import tkinter as tk # tk.TkVersion == tk.TclVersion == 8.6
import pyautogui as pg # pg.__version__ == '0.9.36'
#running with Python 3.6.1 in Windows 10
class App(tk.Tk):
    def __init__(self):
        super().__init__()
        self.geometry('200x200+300+400')
        actionButton = tk.Button(self,
                                 text='highlight, then copy, then print',
                                ## command=self.highlight_then_copy_then_print())#OLD COMMAND
                                 command=self.call_function_outside_main_loop())#NEW COMMAND for Update
        actionButton.pack()
    ###New Code Section For Update###
    def call_function_outside_main_loop(self):
        self.after(5, self.highlight_then_copy_then_print())
    ###End Code Section For Update###

    def highlight_then_copy_then_print(self):
        #I have also tried adding
        #self.clipboard_clear()
        #then,
        #self.clipboard_append('')
        #to the beginning of the function...
        pg.moveTo(100,150)
        pg.dragRel(200,40,
                   duration=1.5,
                   pause=.2)
        pg.hotkey('ctrl', 'c',pause=.2)
        #I have also tried 
##        pg.rightClick(238,160, pause=.15)#right click on selected text
##        pg.typewrite('c',pause=.15)#press C (as shortcut to copy option)
        clipboardText = self.clipboard_get()
        print(clipboardText)
        return None
    
if __name__ == '__main__':
    app = App()

As a workarounds I've the followign, with various degrees of success: First, instantiating an variable, then using a while loop to periodically test the clipboard_get function via a Try/Except statementList item. e.g.

s = None
while s == None:
    try:
        s = self.clipboard_get()
    except:
        #I have tried the below commented out lines in various combinations
        tk.time.sleep(.2)
##        self.update_idletasks()
##        self.update()
##        self.clipboard_clear()
##        self.clipboard_append('')
##        tk.time.sleep(.2)
##        self.separateFunction# a separate function that just highlights and then does ctrl+c without the use of tkinter...
##        tk.time.sleep(.2)

Additional Notes:

  • Adding the while loop helps sometimes, increasing pauses between the functions seems to help as well. Although I have noticed instances where the it seems like no matter what I try, I can't use tk.clipboard_get() reliably until exiting the function.
  • I've noticed the problem is worse when copying text from different applications like Excel. For the purpose of this post, assume I am selecting and copying text from a Notepad++ .txt document.
  • In my own attempts to understand this problem, I found that the app.clipboard_get() function is actually a ctypes call using the Win32.h library. This is why I've included these tags.


Solution 1:[1]

Use this code for copying text from clipboard:

import time
from tkinter import Tk

while True:
    r = Tk()
    try:
        result = r.selection_get(selection="CLIPBOARD")
        print(result)
        time.sleep(1)
    except:
        selection = None

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Tanay