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