Search code examples
pythonqtpyqtoverridingpyside

PyQt after override dragEnterEvent and dropEvent cursor donot blinking and change


  1. I write the class for overriding dragEnterEvent and dropEvent methods at the QtWidgets.QPlainTextEdit object:
class ChangeMethodsDnDTagList(QtWidgets.QPlainTextEdit):
    def __init__(self, obj):
        super().__init__()
        self.obj = obj  # will be type = BeforeQtWidgets.QPlainTextEdit
        self.obj.dragEnterEvent = self.dragEnterEvent
        self.obj.dropEvent = self.dropEvent

    def dragEnterEvent(self, event):
        if event.mimeData().hasText():
            event.accept()
        else:
            event.ignore()

    def dropEvent(self, event):
        if check_text(event.mimeData().text()):
            if self.obj is not None:
                if self.obj.toPlainText() != '':
                    self.obj.setPlainText(self.obj.toPlainText() + ', ' + event.mimeData().text())
                else:
                    self.obj.setPlainText(event.mimeData().text())
  1. Use it in Application, for override methods in the existing object:
    class Application(QtWidgets.QMainWindow, design.Ui_MainWindow, QtWidgets.QWidget, QtCore.QEvent):
        def __init__(self):
            ...
            super().__init__()
            ...
            self.setupUi(self)
            ...
            ChangeMethodsDnDTagList(self.in_tags_list)
  1. Drag and Drop works well but after that, the cursor freezes and does not update (blinking, change position).

  2. The minimal reproducible example: testform.py:

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

# Form implementation generated from reading ui file 'testform.ui'
#
# Created by: PyQt5 UI code generator 5.15.2
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(502, 271)
        MainWindow.setMinimumSize(QtCore.QSize(502, 271))
        MainWindow.setMaximumSize(QtCore.QSize(502, 271))
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.in_tags_list = QtWidgets.QPlainTextEdit(self.centralwidget)
        self.in_tags_list.setGeometry(QtCore.QRect(5, 5, 481, 201))
        self.in_tags_list.setInputMethodHints(QtCore.Qt.ImhLatinOnly|QtCore.Qt.ImhMultiLine)
        self.in_tags_list.setPlainText("")
        self.in_tags_list.setObjectName("in_tags_list")
        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

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

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

test.py:

import sys
from PyQt5 import QtWidgets
from PyQt5 import QtCore
import testform as design
import re


class Application(QtWidgets.QMainWindow, design.Ui_MainWindow, QtWidgets.QWidget, QtCore.QEvent):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.setCentralWidget(self.centralwidget)
        ChangeMethodsDnDTagList(self.in_tags_list)


class ChangeMethodsDnDTagList(QtWidgets.QPlainTextEdit):
    def __init__(self, obj):
        super().__init__()
        self.obj = obj  # will be type = BeforeQtWidgets.QPlainTextEdit
        self.obj.dragEnterEvent = self.dragEnterEvent
        self.obj.dropEvent = self.dropEvent

    def dragEnterEvent(self, event):
        if event.mimeData().hasText():
            event.accept()
        else:
            event.ignore()

    def dropEvent(self, event):
        if check_text(event.mimeData().text()):
            if self.obj is not None:
                if self.obj.toPlainText() != '':
                    self.obj.setPlainText(self.obj.toPlainText() + ', ' + event.mimeData().text())
                else:
                    self.obj.setPlainText(event.mimeData().text())


def check_text(text, mask="""^[a-zA-Z0-9_:, \n\t]+$"""):
    """Check input text"""
    match = re.match(mask, text)
    return bool(match)


def main():
    app = QtWidgets.QApplication(sys.argv)
    window = Application()
    window.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

Solution

  • You need to reimplement dragMoveEvent too, it can be identical to dragEnterEvent so just add one line similar to the others:

    class ChangeMethodsDnDTagList(QtWidgets.QPlainTextEdit):
        def __init__(self, obj):
            super().__init__()
            self.obj = obj  # will be type = BeforeQtWidgets.QPlainTextEdit
            self.obj.dragEnterEvent = self.dragEnterEvent
            self.obj.dropEvent = self.dropEvent
    
            self.obj.dragMoveEvent = self.dragEnterEvent
    

    Then include a line in dropEvent to move the cursor to the end of the document after the drop.

        def dropEvent(self, event):
            if check_text(event.mimeData().text()):
                if self.obj is not None:
                    if self.obj.toPlainText() != '':
                        self.obj.setPlainText(self.obj.toPlainText() + ', ' + event.mimeData().text())
                    else:
                        self.obj.setPlainText(event.mimeData().text())
                        
                    self.obj.moveCursor(QtGui.QTextCursor.End)