在python中检测粘贴 [英] Detecting paste in python

查看:249
本文介绍了在python中检测粘贴的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想检测用户何时在ANY应用程序中粘贴了某些内容,因此可以通过将新项目复制到剪贴板中来进行后续处理(用例:我有要从数据库复制的项目列表

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)

然后我需要的是某种方法来检测粘贴何时具有已在另一个应用程序中执行,因此我可以将下一个项目加载到剪贴板中。当我同时使用这三个软件时,我希望它能在Win / Mac / Linux上运行。有想法吗?

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?

推荐答案

Leon's答案指出,在标准条件下,一旦将它们释放到野外,就不太可能检测到复制对象的任何使用。但是,大多数现代OS支持称为延迟渲染的东西。不仅可以在主机和目标之间协商选择的格式,而且不建议在不事先知道大容量内存的情况下复制大容量内存。 Windows和X都提供了一种通过这种机制完全实现所需功能的方法。

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.

我们不必研究每个操作系统如何实现其剪贴板API的细节。一个相当标准的跨平台软件包: PyQt5 。剪贴板访问是通过 QtGui实现的。 QClipBoard 类。您可以通过避免使用便捷方法并使用来触发延迟渲染 setMimeData 。特别是,您将创建一个自定义 实现子类 nofollow noreferrer> retreiveData 可以根据请求进行获取,而不仅仅是将数据存储在剪贴板中。您还必须设置自己的 hasFormat 格式 ,这应该不是问题。这样一来,您就可以根据要求动态协商可用的格式,这通常是延迟渲染的实现方式。

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.

现在,让我们看一个小型应用程序。您在问题中提到,您拥有要复制的第一个项目后要连续复制的项目的列表。让我们做到这一点。我们的自定义 retrieveData 实现将当前选择转换为字符串,以UTF-8或其他格式编码,将选择向前移动,然后将其复制到剪贴板:

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_()

这里的QTimer对象只是一个黑客,可以快速获取单独的线程来运行副本。尝试在Qt空间之外进行复制会引发一些与线程相关的问题。

此处的关键是您不能简单地将文本复制到剪贴板,而是创建占位符对象。您将无法使用 pyperclip 这样的简单界面,还有可能是 tkinter

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.

好的一面是,上面的示例希望向您显示PyQt5对于简单的应用程序而言并不太复杂(对于非简单种类)。也很高兴,大多数操作系统都支持Qt可以锁定的某种形式的延迟渲染。

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.

请记住,延迟渲染只让您知道何时 some 应用程序从剪贴板读取了一个对象,不一定是您想要的对象。实际上,它不必一定是粘贴的:该应用程序可能只是窥视剪贴板。对于问题中描述的简单操作,这可能会很好。如果您想更好地控制通信,请使用更高级的功能,例如特定于操作系统的监视谁可以读取复制的数据,或者使用更强大的解决方案,例如共享内存。

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.

这篇关于在python中检测粘贴的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆