从 QClipboard 复制/粘贴文本冻结程序 [英] Copy/paste text from QClipboard freezes program
问题描述
我有一个 QTableWidget,当单击一行时,它会选择该行中的所有单元格.我正在尝试添加复制"功能,以便在选择行并粘贴到文本编辑器时可以 ^ctrl-c.但是,使用我当前的代码,一旦我 ^ctrl-c 一行,我复制的行就会不断被复制.
I have a QTableWidget that when a row is clicked, it selects all cells in that row. I am trying to add a "copy" functionality so that I can ^ctrl-c when row(s) are selected and paste into a text editor. However, with my current code, once i ^ctrl-c a row, the line that I copied keeps getting copied.
我在我的方法read_clipboard"中实现了一个打印语句,以查看复制的行是否被读取,这就是我发现该行不断被复制的方式,就像在无限循环中一样.
I have implemented a print statement in my method "read_clipboard" to see whether or not the line copied was read, and this is how I found out that the line keeps getting copied as if in an infinite loop.
之前关于 PyQt/Qt 和 QClipboard 的堆栈溢出问题都没有对我有效.
None of the previous stack overflow questions on PyQt/Qt and QClipboard have been effective for me.
def __init__(self):
super(MainWindow, self).__init__()
self.setupUi(self)
self.my_selector = self.my_tableWidget.selectionModel()
# Where I detect the signal to call my "read_clipboard" method
QtGui.QGuiApplication.clipboard().dataChanged.connect(self.read_clipboard)
self.show()
def read_clipboard(self):
selection = self.my_selector.selectedIndexes()
if selection:
print(selection)
QtGui.QGuiApplication.clipboard().clear()
QtGui.QGuiApplication.clipboard().setText(selection)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
mainWin = MainWindow() # Creates MainWindow object
ret = app.exec_()
sys.exit(ret)
当我 ^ctrl-c 一行时,程序会连续打印选择",就好像它处于无限循环中一样,我不知道如何在它只运行一次后停止它,以便我可以复制它一行.
When I ^ctrl-c a row, the program prints the "selection" continuously as if it is in an infinite loop, I don't know how to stop it after it runs just once so that I can just copy that one line.
推荐答案
您不应该以这种方式使用 dataChanged
信号,原因有两个:
You shouldn't use the dataChanged
signal in this way for two reasons:
- 每次剪贴板在整个系统中发生变化时都会调用它;
- 清除剪贴板显然会改变它的内容,导致对
read_clipboard
方法的递归调用;您显然可以按照@furas 的建议暂时断开信号,但第一个问题仍然存在.
- it will be called everytime the clipboard changes in the whole system;
- clearing the clipboard will obviously change its content, resulting in a recursive call to your
read_clipboard
method; you could obviously temporarily disconnect the signal as suggested by @furas, but the first problem will remain.
此外,您不能为 setText
使用 QItemSelectionModel,因为它需要一个字符串.
Also, you can't use a QItemSelectionModel for setText
, as it expects a string.
更好的解决方案是覆盖自定义 QTableWidget 类的 keyPressEvent,以在默认实现对其进行操作之前捕获它的复制"操作:
A better solution is to override the keyPressEvent of a custom QTableWidget class, to catch it's "copy" action before the default implementation acts upon it:
class MyTableWidget(QtWidgets.QTableWidget):
def keyPressEvent(self, event):
if event == QtGui.QKeySequence.Copy:
# set clipboard only if it's not a key repetition
if not event.isAutoRepeat():
QtWidgets.QApplication.clipboard().setText(', '.join(i.data() for i in self.selectedIndexes() if i.data()))
else:
super(MyTableWidget, self).keyPressEvent(event)
另一种类似的可能性是在您的表中安装一个事件过滤器并检查其关键事件:
Another similar possibility is to install an event filter to your table and check for its key events:
class MyWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setupUi(self)
self.my_tableWidget.installEventFilter(self)
def eventFilter(self, source, event):
if source == self.table and event.type() == QtCore.QEvent.KeyPress and event == QtGui.QKeySequence.Copy:
if not event.isAutoRepeat():
QtWidgets.QApplication.clipboard().setText(', '.join(i.data() for i in self.table.selectedIndexes() if i.data()))
# return True to ensure that the event is not actually propagated
# to the table widget, nor its parent(s)
return True
return super(MainWindow, self).eventFilter(source, event)
这篇关于从 QClipboard 复制/粘贴文本冻结程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!