Python Forum

Full Version: Need help with class composition / multiple inheritance / polymorphism (?)
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Trying to share a class (BodySuperClass), which can be either a QTextEdit or a QPlainTextEdit and contains Qt functions such as focusInEvent;

#!/usr/bin/python3
from PyQt5 import QtWidgets


class Text(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.body = Body()
        self.layout = QtWidgets.QVBoxLayout()
        self.layout.addWidget(self.body)
        self.setLayout(self.layout)
        self.show()


class BodySuperClass:
    def focusInEvent(self, event):
        print("Hello world")
        super().focusInEvent(event)


class Body(QtWidgets.QPlainTextEdit, BodySuperClass):
    def __init__(self):
        super().__init__()


app = QtWidgets.QApplication([])
widget = Text()
app.exec()
Which fails with;
Quote:Hello world
Traceback (most recent call last):
File "/tmp/pyScript.py", line 18, in focusInEvent
super().focusInEvent(event)
AttributeError: 'super' object has no attribute 'focusInEvent'

Also tried calling super().__init__() from the Body class, but that does not work;

#!/usr/bin/python3
from PyQt5 import QtWidgets


class Text(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.body = Body()
        self.layout = QtWidgets.QVBoxLayout()
        self.layout.addWidget(self.body)
        self.setLayout(self.layout)
        self.show()


class BodySuperClass:
    def _monkeyInit(self, qTextClass):
        super(qTextClass, self).__init__()

    def focusInEvent(self, event):
        print("Hello world")
        super().focusInEvent(event)


class Body(QtWidgets.QPlainTextEdit, BodySuperClass):
    def __init__(self):
        super().__init__()
        self._monkeyInit(QtWidgets.QPlainTextEdit)


app = QtWidgets.QApplication([])
widget = Text()
app.exec()
Finally, what works is to hardcode inheritance of BodySuperClass to QPlainTextEdit, but I don't like that as when only a QTextEdit object is needed, Body inherits from both;

#!/usr/bin/python3
from PyQt5 import QtWidgets


class Text(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.body = Body()
        self.layout = QtWidgets.QVBoxLayout()
        self.layout.addWidget(self.body)
        self.setLayout(self.layout)
        self.show()


class BodySuperClass(QtWidgets.QPlainTextEdit):
    def focusInEvent(self, event):
        print("Hello world")
        super().focusInEvent(event)


class Body(QtWidgets.QTextEdit, BodySuperClass):
    def __init__(self):
        super().__init__()
        print("QTextEdit:", isinstance(self, QtWidgets.QTextEdit))
        print("QPlainTextEdit:", isinstance(self, QtWidgets.QPlainTextEdit))


app = QtWidgets.QApplication([])
widget = Text()
app.exec()
Quote:QTextEdit: True
QPlainTextEdit: True
Hello world

What would be the best way to achive this?
Why QWidget with Layout, why not QMainWindow?

class Text(QtWidgets.QMainWindow):
    def __init__(self):
        super(Text, self).__init__()
        self.body = Body()
        self.setCentralWidget(self.body)
        self.show()
(May-08-2021, 09:05 PM)Axel_Erfurt Wrote: [ -> ]Why QWidget with Layout, why not QMainWindow?

class Text(QtWidgets.QMainWindow):
    def __init__(self):
        super(Text, self).__init__()
        self.body = Body()
        self.setCentralWidget(self.body)
        self.show()

It is just an example, but since you ask, it is a sticky note application which handle numerous windows simultaneously. As it does not use any of QMainWindow methods, QWidget has less overhead and thus is more appropriated.

https://gitlab.com/william.belanger/qtpa...enix/qtpad
Found this so far;

#!/usr/bin/python3
from PyQt5 import QtWidgets


class Container(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.plainText = PlainText()
        self.richText = RichText()
        self.layout = QtWidgets.QVBoxLayout()
        self.layout.addWidget(self.plainText)
        self.layout.addWidget(self.richText)
        self.setLayout(self.layout)
        self.show()


class AbstractText:
    def focusInEvent(self, event):
        print(self.__class__, ":",
              "QTextEdit=", isinstance(self, QtWidgets.QTextEdit),
              " | QPlainTextEdit=", isinstance(self, QtWidgets.QPlainTextEdit))
        self._super.focusInEvent(self, event)  # super().focusInEvent(event)


class PlainText(QtWidgets.QPlainTextEdit, AbstractText):
    _super = QtWidgets.QPlainTextEdit  # Replaces super() in AbstractText methods

    def __init__(self):
        super().__init__()


class RichText(QtWidgets.QTextEdit, AbstractText):
    _super = QtWidgets.QTextEdit  # Replaces super() in AbstractText methods

    def __init__(self):
        super().__init__()


app = QtWidgets.QApplication([])
widget = Container()
app.exec()
You can use a mixin class.
from PySide2 import QtWidgets
 
class Container(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.plainText = PlainText()
        self.richText = RichText()
        self.layout = QtWidgets.QVBoxLayout()
        self.layout.addWidget(self.plainText)
        self.layout.addWidget(self.richText)
        self.setLayout(self.layout)
        self.show()
 
class FocusMixin:
    """Insert special focusInEvent to existing widgets"""
    def __init__(self, *args, **kvargs):
        super().__init__(*args, **kvargs)

    def focusInEvent(self, event):
        print(self.__class__, ":",
              "QTextEdit=", isinstance(self, QtWidgets.QTextEdit),
              " | QPlainTextEdit=", isinstance(self, QtWidgets.QPlainTextEdit))
        super().focusInEvent(event)
 
class PlainText(FocusMixin, QtWidgets.QPlainTextEdit):
    """PlainText with focus mixin"""

class RichText(FocusMixin, QtWidgets.QTextEdit):
    """RichText with focus mixin"""

app = QtWidgets.QApplication([])
widget = Container()
app.exec_()