Copy/paste text from QClipboard freezes program

喜欢而已 提交于 2021-02-10 14:14:55

问题


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.

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.

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)

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.


回答1:


You shouldn't use the dataChanged signal in this way for two reasons:

  • 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.

Also, you can't use a QItemSelectionModel for setText, as it expects a string.

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)


来源:https://stackoverflow.com/questions/57260037/copy-paste-text-from-qclipboard-freezes-program

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!