python自动识别粘贴复制_在python中检测粘贴

该博客讨论了如何在Python中实现一个功能,当用户在任何应用中完成粘贴操作后,能自动将下一个项目放入剪贴板。通过使用跨平台的PyQt5库,创建了一个自定义的QMimeData子类,实现延迟渲染机制,从而在读取剪贴板内容时动态提供数据,并确保在Win/Mac/Linux上都能工作。
摘要由CSDN通过智能技术生成

I'm wanting to detect when the user has pasted something in ANY application, so I can follow it up with copying a new item into the clipboard (Use case: I have a list of items I'm copying from a database one-by-one into a web-page, and would like to automatically put the next one in the clipboard once I've finished pasting.)

Currently I have a button using Tkinter that copies a field when pressed using the following code.

self.root.clipboard_clear()

self.root.clipboard_append(text)

What I need then would be some way to detect when a paste has been performed in another application, so I can then load in the next item into the clipboard. I would like it to work on Win/Mac/Linux as I work across all three. Any ideas?

解决方案

As Leon's answer points out, under standard conditions, it is unlikely that you will be able to detect any use of copied objects once you've released them into the wild. However, most modern OSes support something called "delayed rendering". Not only can the format of the selection be negotiated between host and destination, but it is not advisable to copy large pieces of memory without first knowing where they are going. Both Windows and X provide a way of doing exactly what you want through this mechanism.

Rather than go into the details of how each OS implements their clipboard API, let's look at a fairly standard cross-plarform package: PyQt5. Clipboard access is implemented through the QtGui.QClipBoard class. You can trigger delayed rendering by avoiding the convenience methods and using setMimeData. In particular, you would create a custom QtCore.QMimeData subclass that implements retreiveData to fetch upon request rather than just storing the data in the clipboard. You will also have to set up your own implementations of hasFormat and formats, which should not be a problem. This will allow you to dynamically negotiate the available formats upon request, which is how delayed rendering is normally implemented.

So now let's take a look at a small application. You mentioned in the question that you have a list of items that you would like to copy successively once the first one has been copied. Let's do exactly that. Our custom retrieveData implementation will convert the current selection to a string, encode it in UTF-8 or whatever, move the selection forward, and copy that into the clipboard:

from PyQt5.QtCore import Qt, QMimeData, QStringListModel, QTimer, QVariant

from PyQt5.QtGui import QClipboard

from PyQt5.QtWidgets import QAbstractItemView, QApplication, QListView

class MyMimeData(QMimeData):

FORMATS = {'text/plain'}

def __init__(self, item, hook=None):

super().__init__()

self.item = item

self.hook = hook

def hasFormat(self, fmt):

return fmt in self.FORMATS

def formats(self):

# Ensure copy

return list(self.FORMATS)

def retrieveData(self, mime, type):

if self.hasFormat(mime):

if self.hook:

self.hook()

return self.item

return QVariant()

class MyListView(QListView):

def keyPressEvent(self, event):

if event.key() == Qt.Key_C and event.modifiers() & Qt.ControlModifier:

self.copy()

else:

super().keyPressEvent(event)

def nextRow(self):

current = self.selectedIndexes()[0]

row = None

if current:

row = self.model().index(current.row() + 1, current.column())

if row is None or row.row() == -1:

row = self.model().index(0, current.column())

self.setCurrentIndex(row)

QTimer.singleShot(1, self.copy)

def copy(self, row=None):

if row is None:

row = self.selectedIndexes()[0]

data = MyMimeData(row.data(), self.nextRow)

QApplication.clipboard().setMimeData(data, QClipboard.Clipboard)

model = QStringListModel([

"First", "Second", "Third", "Fourth", "Fifth",

"Sixth", "Seventh", "Eighth", "Ninth", "Tenth",

])

app = QApplication([])

view = MyListView()

view.setSelectionMode(QAbstractItemView.SingleSelection)

view.setModel(model)

view.show()

app.exec_()

The QTimer object here is just a hack to quickly get a separate thread to run the copy. Attempting to copy outside Qt space triggers some thread-related problems.

The key here is that you can not simply copy text to the clipboard, but rather create a placeholder object. You will not be able to use a simple interface like pyperclip, and likely tkinter.

On the bright side, the above example hopefully shows you that PyQt5 is not too complex for a simple application (and definitely a good choice for the non-simple kind). It is also nice that most operating systems support some form of delayed rendering in some form that Qt can latch on to.

Keep in mind that delayed rendering only lets you know when an object is read from the clipboard by some application, not necessarily the one you want. In fact it doesn't have to be a "paste": the application could just be peeking into the clipboard. For the simple operation described in the question, this will likely be fine. If you want better control over the communication, use something more advanced, like OS-specific monitoring of who reads the copied data, or a more robust solution like shared memory.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值