python - 在python中检测粘贴

标签 python tkinter clipboard

我想检测用户何时在任何应用程序中粘贴了某些内容,因此我可以跟进将新项目复制到剪贴板(用例:我有一个从数据库中复制的项目列表-一个进入网页,并希望在我完成粘贴后自动将下一个放入剪贴板。)

目前我有一个使用 Tkinter 的按钮,使用以下代码在按下时复制一个字段。

self.root.clipboard_clear()
self.root.clipboard_append(text)

然后我需要某种方法来检测何时在另一个应用程序中执行了粘贴,这样我就可以将下一个项目加载到剪贴板中。我希望它在 Win/Mac/Linux 上工作,因为我在这三个方面都工作。有任何想法吗?

最佳答案

Leon's answer指出,在标准条件下,一旦您将复制的对象释放到野外,您就不太可能检测到它们的任何使用。然而,大多数现代操作系统都支持所谓的“延迟渲染”。不仅可以在主机和目的地之间协商选择的格式,而且在不知道它们要去哪里的情况下复制大块内存是不可取的。 Windows 和 X 都提供了一种通过这种机制来做你想做的事的方法。

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

所以现在让我们看一个小应用程序。您在问题中提到,您有一个项目列表,一旦复制了第一个项目,您就想连续复制这些项目。让我们这样做。我们的定制retrieveData实现会将当前选择转换为字符串,以 UTF-8 或其他方式对其进行编码,将选择向前移动,然后将其复制到剪贴板中:

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 对象只是一个快速获取单独线程来运行副本的 hack。尝试在 Qt 空间之外复制会触发一些与线程相关的问题。

这里的关键是您不能简单地将文本复制到剪贴板,而是创建一个占位符对象。您将无法使用像 pyperclip 这样的简单界面。 ,并且可能 tkinter .

从好的方面来说,上面的示例希望向您展示 PyQt5 对于简单的应用程序来说并不太复杂(对于非简单的应用程序来说绝对是一个不错的选择)。大多数操作系统都支持某种形式的延迟渲染,而 Qt 可以采用这种形式,这也很好。

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

关于python - 在python中检测粘贴,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48503344/

相关文章:

python - 将图像复制到剪贴板?

Python 2.6 : proper usage of unittest. 测试套件

python - 如何使用 Python 删除 CSV 文件的第二行

python - 从python中的int值转换后更改日期格式

python - 为什么这个带有线程的 Popen 不起作用?

wpf - System.Windows.Clipboard 和 System.Windows.Forms.Clipboard 之间有区别吗?

python - 有没有类似 Python 导出的东西?

events - Tkinter 中的多个键事件绑定(bind) - "Control + E" "Command (apple) + E"等

python - 使用 Tkinter 制作文件选择器 GUI 以显示输入和输出文件

带宏小数分隔符的 Excel 到剪贴板