我正在尝试制作一个基本的 Windows 应用程序,它根据用户输入构建一个字符串,然后将其添加到剪贴板。如何使用 Python 将字符串复制到剪贴板?
26 回答
实际上,pywin32
对于ctypes
这个简单的任务似乎有点过头了。Tkinter
是一个跨平台的 GUI 框架,默认情况下与 Python 一起提供,并具有剪贴板访问方法以及其他很酷的东西。
如果您只需要将一些文本放入系统剪贴板,就可以了:
from Tkinter import Tk
r = Tk()
r.withdraw()
r.clipboard_clear()
r.clipboard_append('i can has clipboardz?')
r.update() # now it stays on the clipboard after the window is closed
r.destroy()
仅此而已,无需使用特定于平台的第三方库。
如果您使用的是 Python 3,请替换TKinter
为tkinter
.
我没有解决方案,只是一种解决方法。
Windows Vista 及更高版本有一个名为的内置命令clip
,该命令从命令行获取命令的输出并将其放入剪贴板。例如,ipconfig | clip
。
因此,我使用模块创建了一个函数,该os
模块接受一个字符串并使用内置的 Windows 解决方案将其添加到剪贴板。
import os
def addToClipBoard(text):
command = 'echo ' + text.strip() + '| clip'
os.system(command)
# Example
addToClipBoard('penny lane')
# Penny Lane is now in your ears, eyes, and clipboard.
然而,正如前面在评论中指出的那样,这种方法的一个缺点是该echo
命令会自动在文本末尾添加换行符。为避免这种情况,您可以使用命令的修改版本:
def addToClipBoard(text):
command = 'echo | set /p nul=' + text.strip() + '| clip'
os.system(command)
如果您使用的是 Windows XP,则只需按照从 Windows XP Pro 的命令提示符直接复制并粘贴到剪贴板中的步骤操作即可。
您还可以使用 ctypes 来利用 Windows API 并避免使用庞大的 pywin32 包。这就是我使用的(请原谅糟糕的风格,但想法就在那里):
import ctypes
# Get required functions, strcpy..
strcpy = ctypes.cdll.msvcrt.strcpy
ocb = ctypes.windll.user32.OpenClipboard # Basic clipboard functions
ecb = ctypes.windll.user32.EmptyClipboard
gcd = ctypes.windll.user32.GetClipboardData
scd = ctypes.windll.user32.SetClipboardData
ccb = ctypes.windll.user32.CloseClipboard
ga = ctypes.windll.kernel32.GlobalAlloc # Global memory allocation
gl = ctypes.windll.kernel32.GlobalLock # Global memory Locking
gul = ctypes.windll.kernel32.GlobalUnlock
GMEM_DDESHARE = 0x2000
def Get():
ocb(None) # Open Clip, Default task
pcontents = gcd(1) # 1 means CF_TEXT.. too lazy to get the token thingy...
data = ctypes.c_char_p(pcontents).value
#gul(pcontents) ?
ccb()
return data
def Paste(data):
ocb(None) # Open Clip, Default task
ecb()
hCd = ga(GMEM_DDESHARE, len(bytes(data,"ascii")) + 1)
pchData = gl(hCd)
strcpy(ctypes.c_char_p(pchData), bytes(data, "ascii"))
gul(hCd)
scd(1, hCd)
ccb()
您可以使用具有内置剪贴板支持的优秀 pandas,但您需要通过 DataFrame。
import pandas as pd
df=pd.DataFrame(['Text to copy'])
df.to_clipboard(index=False,header=False)
最简单的方法是使用pyperclip。在 python 2 和 3 中工作。
要安装此库,请使用:
pip install pyperclip
示例用法:
import pyperclip
pyperclip.copy("your string")
如果要获取剪贴板的内容:
clipboard_content = pyperclip.paste()
如果您可以依赖 Pandas,这是我发现的最简单可靠的方法。但是我不认为这正式成为 Pandas API 的一部分,因此它可能会随着未来的更新而中断。它从 0.25.3 开始工作
from pandas.io import clipboard
clipboard.copy("test")
出于某种原因,我一直无法让 Tk 解决方案为我工作。kapace 的解决方案更可行,但格式与我的风格相反,它不适用于 Unicode。这是一个修改后的版本。
import ctypes
from ctypes.wintypes import BOOL, HWND, HANDLE, HGLOBAL, UINT, LPVOID
from ctypes import c_size_t as SIZE_T
OpenClipboard = ctypes.windll.user32.OpenClipboard
OpenClipboard.argtypes = HWND,
OpenClipboard.restype = BOOL
EmptyClipboard = ctypes.windll.user32.EmptyClipboard
EmptyClipboard.restype = BOOL
GetClipboardData = ctypes.windll.user32.GetClipboardData
GetClipboardData.argtypes = UINT,
GetClipboardData.restype = HANDLE
SetClipboardData = ctypes.windll.user32.SetClipboardData
SetClipboardData.argtypes = UINT, HANDLE
SetClipboardData.restype = HANDLE
CloseClipboard = ctypes.windll.user32.CloseClipboard
CloseClipboard.restype = BOOL
CF_UNICODETEXT = 13
GlobalAlloc = ctypes.windll.kernel32.GlobalAlloc
GlobalAlloc.argtypes = UINT, SIZE_T
GlobalAlloc.restype = HGLOBAL
GlobalLock = ctypes.windll.kernel32.GlobalLock
GlobalLock.argtypes = HGLOBAL,
GlobalLock.restype = LPVOID
GlobalUnlock = ctypes.windll.kernel32.GlobalUnlock
GlobalUnlock.argtypes = HGLOBAL,
GlobalSize = ctypes.windll.kernel32.GlobalSize
GlobalSize.argtypes = HGLOBAL,
GlobalSize.restype = SIZE_T
GMEM_MOVEABLE = 0x0002
GMEM_ZEROINIT = 0x0040
unicode_type = type(u'')
def get():
text = None
OpenClipboard(None)
handle = GetClipboardData(CF_UNICODETEXT)
pcontents = GlobalLock(handle)
size = GlobalSize(handle)
if pcontents and size:
raw_data = ctypes.create_string_buffer(size)
ctypes.memmove(raw_data, pcontents, size)
text = raw_data.raw.decode('utf-16le').rstrip(u'\0')
GlobalUnlock(handle)
CloseClipboard()
return text
def put(s):
if not isinstance(s, unicode_type):
s = s.decode('mbcs')
data = s.encode('utf-16le')
OpenClipboard(None)
EmptyClipboard()
handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, len(data) + 2)
pcontents = GlobalLock(handle)
ctypes.memmove(pcontents, data, len(data))
GlobalUnlock(handle)
SetClipboardData(CF_UNICODETEXT, handle)
CloseClipboard()
paste = get
copy = put
自从首次创建此答案以来,上述内容发生了变化,以更好地应对扩展的 Unicode 字符和 Python 3。它已经在 Python 2.7 和 3.5 中进行了测试,甚至可以与\U0001f601 ()
.
2021-10-26 更新:这在 Windows 7 和 Python 3.8 中对我来说非常有用。然后我得到了一台装有 Windows 10 和 Python 3.10 的新计算机,它以与评论中所示相同的方式失败了。 这个帖子给了我答案。来自的函数ctypes
没有正确指定参数和返回类型,并且默认值与 64 位值不一致。我已经修改了上面的代码以包含缺失的信息。
我尝试了各种解决方案,但这是通过我测试的最简单的解决方案:
#coding=utf-8
import win32clipboard # http://sourceforge.net/projects/pywin32/
def copy(text):
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardText(text, win32clipboard.CF_UNICODETEXT)
win32clipboard.CloseClipboard()
def paste():
win32clipboard.OpenClipboard()
data = win32clipboard.GetClipboardData(win32clipboard.CF_UNICODETEXT)
win32clipboard.CloseClipboard()
return data
if __name__ == "__main__":
text = "Testing\nthe “clip—board”: "
try: text = text.decode('utf8') # Python 2 needs decode to make a Unicode string.
except AttributeError: pass
print("%r" % text.encode('utf8'))
copy(text)
data = paste()
print("%r" % data.encode('utf8'))
print("OK" if text == data else "FAIL")
try: print(data)
except UnicodeEncodeError as er:
print(er)
print(data.encode('utf8'))
在 Windows 8.1 上的 Python 3.4 和 Windows 7 上的 Python 2.7 中测试正常。在使用从 Windows 复制的 Unix 换行符读取 Unicode 数据时也是如此。Python 退出后,复制的数据保留在剪贴板上:"Testing
the “clip—board”: "
如果您不想要外部依赖项,请使用此代码(现在是跨平台的一部分pyperclip
- C:\Python34\Scripts\pip install --upgrade pyperclip
):
def copy(text):
GMEM_DDESHARE = 0x2000
CF_UNICODETEXT = 13
d = ctypes.windll # cdll expects 4 more bytes in user32.OpenClipboard(None)
try: # Python 2
if not isinstance(text, unicode):
text = text.decode('mbcs')
except NameError:
if not isinstance(text, str):
text = text.decode('mbcs')
d.user32.OpenClipboard(0)
d.user32.EmptyClipboard()
hCd = d.kernel32.GlobalAlloc(GMEM_DDESHARE, len(text.encode('utf-16-le')) + 2)
pchData = d.kernel32.GlobalLock(hCd)
ctypes.cdll.msvcrt.wcscpy(ctypes.c_wchar_p(pchData), text)
d.kernel32.GlobalUnlock(hCd)
d.user32.SetClipboardData(CF_UNICODETEXT, hCd)
d.user32.CloseClipboard()
def paste():
CF_UNICODETEXT = 13
d = ctypes.windll
d.user32.OpenClipboard(0)
handle = d.user32.GetClipboardData(CF_UNICODETEXT)
text = ctypes.c_wchar_p(handle).value
d.user32.CloseClipboard()
return text
看起来您需要将 win32clipboard 添加到您的站点包中。它是pywin32 包的一部分
如果你不喜欢这个名字,你可以使用派生模块clipboard
。
安装后,导入:
import clipboard
然后你可以像这样复制:
clipboard.copy("This is copied")
您还可以粘贴复制的文本:
clipboard.paste()
使用pyperclip
模块
使用 pip 安装pip install pyperclip
。
将文本复制"Hello World!"
到剪贴板
import pyperclip
pyperclip.copy('Hello World!')
您可以使用Ctrl+V
任何地方将其粘贴到某处。
使用python粘贴复制的文本
pyperclip.paste() # This returns the copied text of type <class 'str'>
小部件还有一个名为.clipboard_get()
返回剪贴板内容的方法(除非根据剪贴板中的数据类型发生某种错误)。
该clipboard_get()
错误报告中提到了该方法:http:
//bugs.python.org/issue14777
奇怪的是,我通常参考的常见(但非官方)在线 TkInter 文档资源中没有提到这种方法。
我认为有一个更简单的解决方案。
name = input('What is your name? ')
print('Hello %s' % (name) )
然后在命令行中运行你的程序
蟒蛇欢迎者.py | 夹子
这会将文件的输出通过管道传输到剪贴板
并非所有答案都适用于我的各种 python 配置,因此此解决方案仅使用 subprocess 模块。但是,copy_keyword
必须pbcopy
适用于 Mac 或clip
Windows:
import subprocess
subprocess.run('copy_keyword', universal_newlines=True, input='New Clipboard Value ')
下面是一些更广泛的代码,可以自动检查当前操作系统是什么:
import platform
import subprocess
copy_string = 'New Clipboard Value '
# Check which operating system is running to get the correct copying keyword.
if platform.system() == 'Darwin':
copy_keyword = 'pbcopy'
elif platform.system() == 'Windows':
copy_keyword = 'clip'
subprocess.run(copy_keyword, universal_newlines=True, input=copy_string)
除了Mark Ransom使用 ctypes 的回答:这不适用于(所有?)x64 系统,因为句柄似乎被截断为 int 大小。显式定义参数和返回值有助于克服这个问题。
import ctypes
import ctypes.wintypes as w
CF_UNICODETEXT = 13
u32 = ctypes.WinDLL('user32')
k32 = ctypes.WinDLL('kernel32')
OpenClipboard = u32.OpenClipboard
OpenClipboard.argtypes = w.HWND,
OpenClipboard.restype = w.BOOL
GetClipboardData = u32.GetClipboardData
GetClipboardData.argtypes = w.UINT,
GetClipboardData.restype = w.HANDLE
EmptyClipboard = u32.EmptyClipboard
EmptyClipboard.restype = w.BOOL
SetClipboardData = u32.SetClipboardData
SetClipboardData.argtypes = w.UINT, w.HANDLE,
SetClipboardData.restype = w.HANDLE
CloseClipboard = u32.CloseClipboard
CloseClipboard.argtypes = None
CloseClipboard.restype = w.BOOL
GHND = 0x0042
GlobalAlloc = k32.GlobalAlloc
GlobalAlloc.argtypes = w.UINT, w.ctypes.c_size_t,
GlobalAlloc.restype = w.HGLOBAL
GlobalLock = k32.GlobalLock
GlobalLock.argtypes = w.HGLOBAL,
GlobalLock.restype = w.LPVOID
GlobalUnlock = k32.GlobalUnlock
GlobalUnlock.argtypes = w.HGLOBAL,
GlobalUnlock.restype = w.BOOL
GlobalSize = k32.GlobalSize
GlobalSize.argtypes = w.HGLOBAL,
GlobalSize.restype = w.ctypes.c_size_t
unicode_type = type(u'')
def get():
text = None
OpenClipboard(None)
handle = GetClipboardData(CF_UNICODETEXT)
pcontents = GlobalLock(handle)
size = GlobalSize(handle)
if pcontents and size:
raw_data = ctypes.create_string_buffer(size)
ctypes.memmove(raw_data, pcontents, size)
text = raw_data.raw.decode('utf-16le').rstrip(u'\0')
GlobalUnlock(handle)
CloseClipboard()
return text
def put(s):
if not isinstance(s, unicode_type):
s = s.decode('mbcs')
data = s.encode('utf-16le')
OpenClipboard(None)
EmptyClipboard()
handle = GlobalAlloc(GHND, len(data) + 2)
pcontents = GlobalLock(handle)
ctypes.memmove(pcontents, data, len(data))
GlobalUnlock(handle)
SetClipboardData(CF_UNICODETEXT, handle)
CloseClipboard()
#Test run
paste = get
copy = put
copy("Hello World!")
print(paste())
使用 python 的剪贴板库!
import clipboard as cp
cp.copy("abc")
剪贴板现在包含“abc”。快乐粘贴!
你也可以使用 >clipboard
import clipboard
def copy(txt):
clipboard.copy(txt)
copy("your txt")
import wx
def ctc(text):
if not wx.TheClipboard.IsOpened():
wx.TheClipboard.Open()
data = wx.TextDataObject()
data.SetText(text)
wx.TheClipboard.SetData(data)
wx.TheClipboard.Close()
ctc(text)
这是雾化器的改进答案。
注意它们之间的 2 个调用update()
和200 ms
延迟。由于剪贴板状态不稳定,它们可以保护冻结的应用程序:
from Tkinter import Tk
import time
r = Tk()
r.withdraw()
r.clipboard_clear()
r.clipboard_append('some string')
r.update()
time.sleep(.2)
r.update()
r.destroy()
我在这里分享的片段利用了格式化文本文件的能力:如果你想将复杂的输出复制到剪贴板怎么办?(在列中说一个 numpy 数组或某个东西的列表)
import subprocess
import os
def cp2clip(clist):
#create a temporary file
fi=open("thisTextfileShouldNotExist.txt","w")
#write in the text file the way you want your data to be
for m in clist:
fi.write(m+"\n")
#close the file
fi.close()
#send "clip < file" to the shell
cmd="clip < thisTextfileShouldNotExist.txt"
w = subprocess.check_call(cmd,shell=True)
#delete the temporary text file
os.remove("thisTextfileShouldNotExist.txt")
return w
仅适用于 Windows,我猜可以适用于 linux 或 mac。可能有点复杂...
例子:
>>>cp2clip(["ET","phone","home"])
>>>0
任何文本编辑器中的 Ctrl+V :
ET
phone
home
你可以使用winclip32模块!安装:
pip install winclip32
复印:
import winclip32
winclip32.set_clipboard_data(winclip32.UNICODE_STD_TEXT, "some text")
要得到:
import winclip32
print(winclip32.get_clipboard_data(winclip32.UNICODE_STD_TEXT))
在 Windows 上,您可以使用它。没有外部依赖也不必打开子流程:
import win32clipboard
def to_clipboard(txt):
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardText(txt)
win32clipboard.CloseClipboard()
如果(且仅当)应用程序已经使用 Qt,您可以使用它(优点是没有额外的第三方依赖)
from PyQt5.QtWidgets import QApplication
clipboard = QApplication.clipboard()
# get text (if there's text inside instead of e.g. file)
clipboard.text()
# set text
clipboard.setText(s)
这要求已经构造了一个 Qt 应用程序对象,因此除非应用程序已经使用 Qt,否则不应使用它。
此外,像往常一样,在 X 系统(可能还有其他系统)中,除非您使用 parcellite 或 xclipboard 之类的东西,否则内容只会持续到应用程序存在为止。
文档:
复制剪贴板的代码片段:
在名为 ( clipboard.py )的模块中创建包装 Python 代码:
import clr
clr.AddReference('System.Windows.Forms')
from System.Windows.Forms import Clipboard
def setText(text):
Clipboard.SetText(text)
def getText():
return Clipboard.GetText()
然后将上述模块导入您的代码中。
import io
import clipboard
code = clipboard.getText()
print code
code = "abcd"
clipboard.setText(code)
我必须感谢 IronPython 中的博客文章剪贴板访问。
你可以试试这个:
command = 'echo content |clip'
subprocess.check_call(command, shell=True)