Search code examples
pythonpyqtpyqt5pyqt4qvariantanimation

TypeError: PyQt4.QtCore.QVariantAnimation represents a C++ abstract class and cannot be instantiated


I have this PyQt5 snippet that I'm trying to convert into PyQt4. The PyQt5 version works great but when I try to convert into PyQt4, I get this error. I removed QtWidgets but I still receive this error. I also tried to just instantiate self.animation = QtCore.QVariantAnimation() but still get the same error.

Traceback (most recent call last):
  File ".\test1.py", line 29, in <module>
    lineedit = LineEdit()
  File ".\test1.py", line 13, in __init__
    valueChanged=self.on_color_change,
TypeError: PyQt4.QtCore.QVariantAnimation represents a C++ abstract class and cannot be instantiated

Working PyQt5 version

import sys
from PyQt5 import QtCore, QtGui, QtWidgets

class LineEdit(QtWidgets.QLineEdit):
    def __init__(self):
        super(LineEdit, self).__init__()
        self.textChanged.connect(self.start_animation)

        self.animation = QtCore.QVariantAnimation(
            startValue=QtGui.QColor(255, 127, 127),
            endValue=QtGui.QColor(255, 255, 255),
            duration=1000,
            valueChanged=self.on_color_change,
        )

    @QtCore.pyqtSlot()
    def start_animation(self):
        if self.animation.state() == QtCore.QAbstractAnimation.Running:
            self.animation.stop()
        self.animation.start()

    @QtCore.pyqtSlot(QtCore.QVariant)
    @QtCore.pyqtSlot(QtGui.QColor)
    def on_color_change(self, color):
        self.setStyleSheet("QLineEdit{background-color: %s}" % (color.name(),))

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    lineedit = LineEdit()
    lineedit.show()
    sys.exit(app.exec_())

Broken PyQt4 version

import sys
from PyQt4 import QtCore, QtGui

class LineEdit(QtGui.QLineEdit):
    def __init__(self):
        super(LineEdit, self).__init__()
        self.textChanged.connect(self.start_animation)

        self.animation = QtCore.QVariantAnimation(
            startValue=QtGui.QColor(255, 127, 127),
            endValue=QtGui.QColor(255, 255, 255),
            duration=1000,
            valueChanged=self.on_color_change,
        )

    @QtCore.pyqtSlot()
    def start_animation(self):
        if self.animation.state() == QtCore.QAbstractAnimation.Running:
            self.animation.stop()
        self.animation.start()

    @QtCore.pyqtSlot(QtCore.QVariant)
    @QtCore.pyqtSlot(QtGui.QColor)
    def on_color_change(self, color):
        self.setStyleSheet("QLineEdit{background-color: %s}" % (color.name(),))

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    lineedit = LineEdit()
    lineedit.show()
    sys.exit(app.exec_())

Does anyone know how to fix this?


Solution

  • In Qt4 updateCurrentValue() is a pure virtual method that needs to be implemented, in the case of Qt5 it is changing to be only a virtual method, in the first case C++ forces to implement it but with the change of Qt5 it is no longer necessary, so the solution is implement that method:

    # ...
    class VariantAnimation(QtCore.QVariantAnimation):
        def updateCurrentValue(self, value):
            pass
    
    
    class LineEdit(QtGui.QLineEdit):
        def __init__(self):
            super(LineEdit, self).__init__()
            self.textChanged.connect(self.start_animation)
    
            self.animation = VariantAnimation(
                startValue=QtGui.QColor(255, 127, 127),
                endValue=QtGui.QColor(255, 255, 255),
                duration=1000,
                valueChanged=self.on_color_change,
            )
    
        # ...
    
        @QtCore.pyqtSlot(QtCore.QVariant)
        @QtCore.pyqtSlot(QtGui.QColor)
        def on_color_change(self, color):
            if isinstance(color, QtCore.QVariant):
                color = QtGui.QColor(color)
            self.setStyleSheet("QLineEdit{background-color: %s}" % (color.name(),))
        # ...