将Numpy数组复制到Windows上的剪贴板而不依赖于win32?

vx6bjr1n  于 5个月前  发布在  Windows
关注(0)|答案(2)|浏览(72)

How to paste a Numpy array to Excel的主要答案是在剪贴板中复制一个Numpy数组,准备粘贴到Excel中:

import numpy as np
import win32clipboard as clipboard
def toClipboardForExcel(array):
    array_string = "\r\n".join("\t".join(line.astype(str)).replace("\n","") for line in array)
    clipboard.OpenClipboard()
    clipboard.EmptyClipboard()
    clipboard.SetClipboardText(array_string)
    clipboard.CloseClipboard()
Y = np.arange(64).reshape((8, 8))
toClipboardForExcel(Y)

字符串

是否可以在没有额外的win32包依赖的情况下做到这一点?(我目前在我的项目中没有使用它,我想避免只为剪贴板添加它,注意:我也不使用pandas

我已经尝试过os.system(echo string | clip),但它不适用于多行内容(包含\n)。
或者OpenClipboardSetClipboardText等可以通过ctypes访问(我已经在使用了)?
注意:这不是Python script to copy text to clipboard的重复,因为后者是通用的,并且具有额外的依赖性,在我的问题中,我们希望避免新的依赖性。

wnrlj8wa

wnrlj8wa1#

下面是一个ctypes-only示例,用于在剪贴板上设置任何Python str类型的文本并将其读回。请注意,文本不应包含null,因为CF_UNICODETEXT类型预期是以null结尾的文本。

import ctypes as ct
import ctypes.wintypes as w

CF_UNICODETEXT = 13
NO_ERROR = 0
SIZE_T = ct.c_size_t
GMEM_MOVEABLE = 0x0002

# Error handlers to raise exceptions on failure.

def boolcheck(result, func, args):
    if not result:
        raise ct.WinError(ct.get_last_error())

def nullcheck(result, func, args):
    if result is None:
        raise ct.WinError(ct.get_last_error())
    return result

def zeroerrorcheck(result, func, args):
    if not result:
        err = ct.get_last_error()
        if err != NO_ERROR:
            raise ct.WinError(err)
    return result

# Capture GetLastError() code after each call.
# Fully specify argtypes and restype for ctypes type-checking.

kernel32 = ct.WinDLL('kernel32', use_last_error=True)
GlobalLock = kernel32.GlobalLock
GlobalLock.argtypes = w.HGLOBAL,
GlobalLock.restype = w.LPVOID
GlobalLock.errcheck = nullcheck
GlobalAlloc = kernel32.GlobalAlloc
GlobalAlloc.argtypes = w.UINT, SIZE_T
GlobalAlloc.restype = w.HGLOBAL
GlobalAlloc.errcheck = nullcheck
GlobalUnlock = kernel32.GlobalUnlock
GlobalUnlock.argtypes = w.HGLOBAL,
GlobalUnlock.restype = w.BOOL
GlobalUnlock.errcheck = zeroerrorcheck

user32 = ct.WinDLL('user32', use_last_error=True)
OpenClipboard = user32.OpenClipboard
OpenClipboard.argtypes = w.HWND,
OpenClipboard.restype = w.BOOL
OpenClipboard.errcheck = boolcheck
GetClipboardData = user32.GetClipboardData
GetClipboardData.argtypes = w.UINT,
GetClipboardData.restype = w.HANDLE
GetClipboardData.errcheck = nullcheck
SetClipboardData = user32.SetClipboardData
SetClipboardData.argtypes = w.UINT, w.HANDLE
SetClipboardData.restype = w.HANDLE
SetClipboardData.errcheck = nullcheck
CloseClipboard = user32.CloseClipboard
CloseClipboard.argtypes = ()
CloseClipboard.restype = w.BOOL
CloseClipboard.errcheck = boolcheck
EmptyClipboard = user32.EmptyClipboard
EmptyClipboard.argtypes = ()
EmptyClipboard.restype = w.BOOL
EmptyClipboard.errcheck = boolcheck
GetForegroundWindow = user32.GetForegroundWindow
GetForegroundWindow.argtypes = ()
GetForegroundWindow.restype = w.HWND

def get_clipboard_text():
    OpenClipboard(GetForegroundWindow())
    hmem = GetClipboardData(CF_UNICODETEXT)
    pmem = GlobalLock(hmem)
    text = ct.wstring_at(pmem)
    GlobalUnlock(hmem)
    CloseClipboard()
    return text

def set_clipboard_text(text):
    ztext = text + '\x00'  # null terminator required
    OpenClipboard(None)
    EmptyClipboard()
    hmem = GlobalAlloc(GMEM_MOVEABLE, len(ztext) * ct.sizeof(w.WCHAR))
    pmem = GlobalLock(hmem)
    btext = ztext.encode('utf-16le')
    ct.memmove(pmem, btext, len(btext))
    GlobalUnlock(hmem)
    SetClipboardData(CF_UNICODETEXT, hmem)
    CloseClipboard()
    
set_clipboard_text('马克')
print(get_clipboard_text())

字符串
根据OpenClipboard文件备注:
如果应用程序在hwnd设置为NULL的情况下调用OpenCacheEmptyClipboard会将剪贴板所有者设置为NULL;这会导致SetClipboardData失败。
我的经验是使用NULL(Python中的None)与OpenClipboard * 一起使用不会 * 导致SetClipboardData失败,但不会阻止其他应用程序在打开时使用剪贴板(潜在的竞争条件?)。当使用有效的Window句柄时,其他应用程序将无法打开剪贴板,直到调用CloseClipboard,所以需要一些重试和错误检查。可能最好使用有效的所有者。我在上面使用了GetForegroundWindow

p5cysglq

p5cysglq2#

我还没有看过所有提供Windows剪贴板功能的库,但它通常不是一个非常简单的事情。Windows需要一些样板,这通常对构建完整的GUI应用程序更有用。剪贴板是一个固有的用户体验的东西,所以它很自然地与GUI相关的功能绑定(比如首先需要一个窗口句柄来打开剪贴板)。
如果您在分销方面遇到挑战,(即:将代码分发到非联网计算机),这使得添加pip依赖项变得困难,我将简单地使用合适的许可证将其复制到您的项目中作为子模块。链接的副本提到Pyperclip,其本身不需要外部依赖项用于windows,并有效地做你想做的事(通过ctypes与windows剪贴板交互)。
如果你真的需要自己实现它,我仍然会参考Pyperclip来学习这个过程的所有细节:
1.创建窗口句柄
1.获取剪贴板控制
1.为字符串分配内存
1.将数据从python字符串复制到分配的内存
1.传递数据到剪贴板
1.清理(不要忘记沿着的错误处理)

相关问题