1

I'm testing a client/server clipboard sharing program (because RDP doesn't for reasons i couldn't find). It works fine, but when i activate the client's clipboard writing code, the server thread crashes about 20 seconds after a copy:

_tkinter.TclError: CLIPBOARD selection doesn't exist or form "STRING" not defined

What am i doing wrong? Here's my code, which i ran in two command windows using python share_clipboard.py S and python share_clipboard.py C localhost:

"""
Share clipboard
by Cees Timmerman
01-12-2014 v0.1
"""

import socket, sys, threading
from time import sleep
try: from tkinter import Tk  # Python 3
except: from Tkinter import Tk

def dec(s):
    return s.decode('utf-8')
def enc(s):
    return s.encode('utf-8')

# http://stackoverflow.com/questions/17453212/multi-threaded-tcp-server-in-python
class ClientThread(threading.Thread):
    def __init__(my, sock):
        threading.Thread.__init__(my)
        my.sock = sock

    def run(my):    
        print("Connection from : %s:%s" % (ip, str(port)))
        #my.sock.send(enc("\nWelcome to the server\n\n"))
        '''
        data = "dummydata"
        while len(data):
            data = dec(clientsock.recv(2048))
            print("Client sent : "+data)
            my.sock.send(enc("You sent me : "+data))
        '''
        old_clip = None
        while True:
            new_clip = tk.clipboard_get()
            if new_clip != old_clip:
                print("New clip: %r" % new_clip)
                old_clip = new_clip
                my.sock.sendall(enc(new_clip))
            sleep(1)
        print("Client disconnected...")

if 1 < len(sys.argv) < 4:
    cs = sys.argv[1]
    ip = sys.argv[2] if len(sys.argv) == 3 else "0.0.0.0"
else:
    print("Usage: %s <C|S> [IP]")
    sys.exit()

tk = Tk()
port = 9999

if cs == "S":

    tcpsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    tcpsock.bind((ip, port))
    threads = []

    # Listen for connections.
    while True:
        tcpsock.listen(4)
        print("\nListening for incoming connections...")
        (clientsock, (ip, port)) = tcpsock.accept()
        newthread = ClientThread(clientsock)
        newthread.start()
        threads.append(newthread)

    # Wait for threads to finish.
    for t in threads:
        t.join()
else:
    clientsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    clientsocket.connect((ip, port))
    while True:
        data = clientsocket.recv(1024)
        print(data)
        #tk.withdraw()
        #tk.clipboard_clear()
        #tk.clipboard_append(data)  # Causes error on server: _tkinter.TclError: CLIPBOARD selection doesn't exist or form "STRING" not defined
        #tk.destroy()
Cees Timmerman
  • 17,623
  • 11
  • 91
  • 124
  • In my experience, Tkinter generally behaves strangely when combined with threading. It may be necessary to design your project so all calls to Tk methods are made only in the main thread. – Kevin Dec 01 '14 at 19:40
  • @Kevin `new_clip = tk.clipboard_get()` in the main server loop (using `tcpsock.settimeout(5)`) didn't help. – Cees Timmerman Dec 01 '14 at 23:13
  • The `clipboard` module works. Too bad Python didn't work out of the box. – Cees Timmerman Dec 01 '14 at 23:52
  • `clipboard` uses `pyperclip` which [can't handle fancy quotes.](https://gist.github.com/CTimmerman/370271d0519f3c8db749) – Cees Timmerman Dec 02 '14 at 19:16
  • `win32clipboard` [correctly handles Unicode](https://gist.github.com/CTimmerman/133cb80100357dde92d8). – Cees Timmerman Dec 03 '14 at 13:43

1 Answers1

0

I found this post when searching solutions for my problem but it does not help so I solved it by myself and post the answer here.

Understanding error message is the first step to solve the problem.

_tkinter.TclError: CLIPBOARD selection doesn't exist or form "STRING" not defined

The message says that there 2 possibilities for this to happen:

  1. CLIPBOARD selection doesn't exist
  2. form "STRING" not defined

<1. CLIPBOARD selection doesn't exist> may be easier to understand. No text has been selected, so the clipboard is empty, so tk.clipboard_get() produced error.

<2. form "STRING" not defined> is harder to understand. Below is the reference page for clipboard_get() method : clipboard_get

The reference says that Tkinter sets STRING as default type for the value that returned by clipboard_get() . So if there is something else currently in your clipboard (file names, etc), error may happend (you accidentially copy files instead of text ?)

Solution

My problem was to handle Copying the current text in the Entry Widget, so I solved my issue by:

  1. Clear the clipboard first with clipboard_clear
  2. Select all text present in the widget
  3. Append selected text to the clipboard with clipboard_append

You have a different problem so you have to find a suitable solution for you by reading references.

References

Tung Linh
  • 79
  • 1
  • 4