Copy/paste 来自 QClipboard 的文本冻结程序
Copy/paste text from QClipboard freezes program
我有一个 QTableWidget,当单击一行时,它会选择该行中的所有单元格。我正在尝试添加 "copy" 功能,以便在选择行时可以按 ^ctrl-c 并将其粘贴到文本编辑器中。但是,使用我当前的代码,一旦我 ^ctrl-c 一行,我复制的行就会不断被复制。
我在我的方法 "read_clipboard" 中实现了一个 print 语句来查看复制的行是否被读取,这就是我发现该行不断被复制的方式,就像在无限循环中一样。
None之前关于PyQt/Qt和QClipboard的stack overflow问题对我有效
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 一行时,程序连续打印 "selection" 就好像它在无限循环中一样,我不知道如何在它运行一次后停止它以便我可以只复制那一行。
您不应该以这种方式使用 dataChanged
信号,原因有二:
- 每次剪贴板在整个系统中发生变化时都会被调用;
- 清除剪贴板显然会改变其内容,导致递归调用您的
read_clipboard
方法;您显然可以按照@furas 的建议暂时断开信号,但第一个问题仍然存在。
此外,您不能将 QItemSelectionModel 用于 setText
,因为它需要一个字符串。
更好的解决方案是重写自定义 QTableWidget class 的 keyPressEvent,以便在默认实现作用于它之前捕获它的 "copy" 操作:
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)
另一种类似的可能性是为您的 table 安装事件过滤器并检查其关键事件:
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)
我有一个 QTableWidget,当单击一行时,它会选择该行中的所有单元格。我正在尝试添加 "copy" 功能,以便在选择行时可以按 ^ctrl-c 并将其粘贴到文本编辑器中。但是,使用我当前的代码,一旦我 ^ctrl-c 一行,我复制的行就会不断被复制。
我在我的方法 "read_clipboard" 中实现了一个 print 语句来查看复制的行是否被读取,这就是我发现该行不断被复制的方式,就像在无限循环中一样。
None之前关于PyQt/Qt和QClipboard的stack overflow问题对我有效
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 一行时,程序连续打印 "selection" 就好像它在无限循环中一样,我不知道如何在它运行一次后停止它以便我可以只复制那一行。
您不应该以这种方式使用 dataChanged
信号,原因有二:
- 每次剪贴板在整个系统中发生变化时都会被调用;
- 清除剪贴板显然会改变其内容,导致递归调用您的
read_clipboard
方法;您显然可以按照@furas 的建议暂时断开信号,但第一个问题仍然存在。
此外,您不能将 QItemSelectionModel 用于 setText
,因为它需要一个字符串。
更好的解决方案是重写自定义 QTableWidget class 的 keyPressEvent,以便在默认实现作用于它之前捕获它的 "copy" 操作:
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)
另一种类似的可能性是为您的 table 安装事件过滤器并检查其关键事件:
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)