I have a small application that the user can interact with as a command line. I want the user to be able to copy to the Windows clipboard information that the application has just displayed on-screen. Obviously, the user can do this manually, but it takes several steps: right-click on the window, select "Mark", select the rectangle of text, and press Enter to copy it. I want to allow the user to do this automatically by typing a short command like "cb" or "copy".
Per this answer, an easy way to get clipboard functionality is using the tkinter library. This does indeed work well. However, I find that when my application starts up, it loses the focus. It seems that a hidden window (opened by Tk()
and then hidden by withdraw()
) has it. The act of hiding the window with withdraw()
did not give focus back to my application. This is inconvenient, because having opened the application, the user has to manually switch back to it rather than being able to just begin typing.
I want to create a tkinter object and either give the focus back to my application after I hide the new window, or have my application not lose focus in the first place. How can I do this?
There are various questions already relating to tkinter and focus, but they seem generally to relate to giving focus to the windows that tkinter itself opens, whereas I want to keep focus on the original window of my application, and deny it to the tkinter window.
I'm working at a Windows 8 machine.
Pastebin http://pastebin.com/6jsasiNE
On Windows NT, Windows Server 2003, and Windows 7+
You don't need to use Tkinter
at all to achieve your goal.
clip.py:
import subprocess
def write_to_clipboard(string):
p = subprocess.Popen(['clip'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
p.communicate(input=string)
This code just calls the standard windows clip.exe
utility, pasting whatever passed in the string
variable.
Usage:
from clip import write_to_clipboard
try:
while True:
write_to_clipboard(raw_input())
except KeyboardInterrupt:
pass
On Windows 95, 98, ME, and XP
Those versions of windows don't come with clip.exe
, so here's a python only version:
clip.py:
import subprocess
def write_to_clipboard(string):
p = subprocess.Popen(['python', __file__], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
p.communicate(input=string)
if __name__ == "__main__":
import sys
from Tkinter import Tk
r = Tk()
r.withdraw()
r.clipboard_clear()
r.clipboard_append(sys.stdin.read())
r.update()
r.destroy()
This will work on all version of windows and in face any OS supporting TK
.
Note that you must run the Tk
code in a separate process like this, because even though we call r.destroy()
, Tk
seems to "lock" the clipboard (no other process can access the clipboard until this process has exited).
Reading and Writing Clipboard
If you want to be able to read from the clipboard as well as write to it, this is the solution.
clip.py:
import subprocess
def write(string):
p = subprocess.Popen(['python', __file__, 'write'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
p.communicate(input=string)
def read():
p = subprocess.Popen(['python', __file__, 'read'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
return p.communicate()[0]
if __name__ == "__main__":
import sys
from Tkinter import Tk
if len(sys.argv) != 2:
sys.exit(1)
r = Tk()
try:
r.withdraw()
if sys.argv[1] == "write":
r.clipboard_clear()
r.clipboard_append(sys.stdin.read())
r.update()
elif sys.argv[1] == "read":
sys.stdout.write(r.clipboard_get()),
else:
sys.exit(1)
finally:
r.destroy()
Usage:
import clip
print "clipboard contains: %s" % clip.read()