Курсор `QTextEdit` останавливается после переопределения его `dropEvent`

В программе я хочу принять перетаскивание файла в QTextExit для редактирования определенных его частей.

Перетаскивание работает нормально, однако после перетаскивания файла в QTextEdit курсор QTextEdit застывает (перестает мигать и больше не может быть перемещен).

Вот минимальный пример:

После перетаскивания: (d&d работает нормально, но курсор зависает)

введите здесь описание изображения

Я могу редактировать содержимое в textEdit, но курсор остается видимым после того, как textEdit теряет фокус. введите здесь описание изображения

Код:

# -*- coding: utf-8 -*-
import sys
from PyQt5 import Qt

if __name__ == '__main__':
    Application = Qt.QApplication(sys.argv)
    from Drag_drop_window import Ui_Form # import QtDesigner file

class override_textEdit(Qt.QTextEdit):  # override drop event for QTextEdit
    drop_accepted_signal = Qt.pyqtSignal(str) # the signal sends the file name to other widget
    def __init__(self):
        super(override_textEdit,self).__init__()
        self.setText("123")
        self.setAcceptDrops(True)

    def dropEvent(self, event):
        if len(event.mimeData().urls())==1: # accept event when only one file was dropped
            event.accept()
            self.drop_accepted_signal.emit(event.mimeData().urls()[0].toLocalFile())

        else:
            Qt.QMessageBox.critical(self,"Accept Single File Only","Accept Single File Only",Qt.QMessageBox.Abort)

            event.ignore()

class myWidget(Qt.QWidget):
    def __init__(self):
        super(myWidget, self).__init__()
        self.main = Ui_Form()
        self.main.setupUi(self)

        self.main.textEdit = override_textEdit()
        self.main.verticalLayout.addWidget(self.main.textEdit)
        self.main.textEdit.drop_accepted_signal.connect(self.slot)

        self.show()

    def slot(self,filename):
        self.main.lineEdit.setText(filename) # display file name in lineEdit



if __name__ == '__main__':
    my_Qt_Program = myWidget()

    my_Qt_Program.show()
    sys.exit(Application.exec_())

Drag_drop_window.py, сгенерированный QtDesigner

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'Drag_drop_window.ui'
#
# Created: Sun Apr  5 17:53:03 2015
#      by: PyQt5 UI code generator 5.3.2
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(400, 300)
        self.verticalLayout = QtWidgets.QVBoxLayout(Form)
        self.verticalLayout.setObjectName("verticalLayout")
        self.lineEdit = QtWidgets.QLineEdit(Form)
        self.lineEdit.setObjectName("lineEdit")
        self.verticalLayout.addWidget(self.lineEdit)

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "Form"))

person liyuanhe211    schedule 05.04.2015    source источник


Ответы (1)


Я обнаружил, что добавление следующих четырех строк в конец dropEvent заставляет все работать:

        mimeData = QtCore.QMimeData()
        mimeData.setText("")
        dummyEvent = QtGui.QDropEvent(event.posF(), event.possibleActions(),
                mimeData, event.mouseButtons(), event.keyboardModifiers())

        super(override_textEdit, self).dropEvent(dummyEvent)

Вы переопределили метод dropEvent элемента управления QTextEdit, но не вызываете переопределенный метод суперкласса. Я предполагаю, что в переопределенном методе есть некоторый код очистки, который необходимо запустить, чтобы разобраться с проблемами, которые у вас были с курсором. Однако простой вызов метода суперкласса с событием отбрасывания, т.е.

        super(override_textEdit, self).dropEvent(event)

не делает то, на что вы надеетесь. Это вводит URL-адрес перетащенного файла в элемент управления текстовым редактированием.

Я не обнаружил, что какая-либо комбинация вызовов accept(), ignore() или setDropAction(Qt.IgnoreAction) перед вызовом суперкласса dropEvent имела какой-либо эффект. Я подозреваю, что метод суперкласса принимает собственные решения о том, принимать или игнорировать событие, что может переопределить действия вашего подкласса.

Поэтому вместо этого я создаю «фальшивое» событие перетаскивания, идентичное полученному, за исключением того, что текстовые данные пусты, и передаю это фальшивое событие в суперкласс. Конечно, суперкласс может вставить этот пустой текст куда-нибудь, если захочет, но если он это сделает, это не будет иметь никакого эффекта.

person Luke Woodward    schedule 05.04.2015