Vlad
Vlad

Reputation: 419

How PyQt understand that our class is inheriting from something?

I was recently digging a lot in PyQt and doing some staff with it, but suddenly realized , I don't understand some basic staff which I was doing. How class which inherits let's say from QGraphicsView becomes QGraphicsView itself or how it becomes QWidget ? Also as far as I understand when you inherit from something , class just getting all the methods from class you inherit. Here is some code below :

import PyQt5.QtWidgets as QtWidgets
import PyQt5.QtCore as QtCore


class First(QtWidgets.QGraphicsView):
    def __init__(self, parent=None):
        super(First, self).__init__(parent)
        print('hello')

class Window(QtWidgets.QDialog):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)

        self.window = 'test'
        self.title = 'test'
        self.size = (1000, 650)
        self.create()

    def create(self):
        self.setWindowTitle(self.title)
        self.resize(QtCore.QSize(*self.size))
        self.graphicsWidget = First(self)

        self.mainLayout = QtWidgets.QVBoxLayout( )
        self.mainLayout.addWidget(self.graphicsWidget)
        self.setLayout(self.mainLayout)

if __name__ == '__main__':
    import sys

    app = QtWidgets.QApplication(sys.argv)
    window = Window( )
    window.setGeometry(500, 300, 800, 600)
    window.show( )
    sys.exit(app.exec_( ))

For example in this code , I made class called 'First' and it's inheriting from QtWidgets.QGraphicsView and then I am adding it as a widget to mainLayout inside my Window class. Until now, I was taking it as a granted and didn't think about it much, but can somebody explain to me how my mainLayout.addWidget() which accepting only QWidgets , understands that in front of him is QWidget ? Because if you do print(type(First)) it will give <class 'sip.wrappertype'> not a widget. Thank you

Upvotes: 0

Views: 1523

Answers (2)

eyllanesc
eyllanesc

Reputation: 243973

The inheritance is aimed at the specialization of a class, that is, the inherited class must have specific characteristics that the class from which it inherits.


QGraphicsView is a QWidget, because if you do the QGraphicsView inherence diagram:

┌--------------┐   ┌--------------┐ 
|   QObject    |   | QPaintDevice |
└------┬-------┘   └-------┬------┘ 
       |                   |
       └---------┬---------┘
                 |
          ┌------┴------┐
          |   QWidget   |
          └------┬------┘
                 |
          ┌------┴------┐
          |   QFrame    |
          └------┬------┘
                 |
       ┌---------┴---------┐
       |QAbstractScrollArea|
       └---------┬---------┘
                 |
       ┌---------┴---------┐
       |   QGraphicsView   |
       └-------------------┘

From it it follows that:

  • QGraphicsView is a QAbstractScrollArea.
  • QGraphicsView is a QFrame.
  • QGraphicsView is a QWidget.
  • QGraphicsView is a QObject.
  • QGraphicsView is a QPaintDevice.

Why print(type(First)) returns <class 'sip.wrappertype'>?

If the docs are reviewed:

[...]
SIP implements two super-types, sip.simplewrapper and sip.wrapper, and a meta-type, sip.wrappertype.

sip.simplewrapper is the super-type of sip.wrapper. The super-type of sip.simplewrapper is object.

sip.wrappertype is the meta-type of both sip.simplewrapper and sip.wrapper. The super-type of sip.wrappertype is type.

sip.wrapper supports the concept of object ownership described in Ownership of Objects and, by default, is the super-type of all the types that SIP generates.
[...]

From it it follows that sip.wrappertype is the metaclass of QObject. And that's what you're doing since type(FooClass) returns the metaclass of FooClass.

If you want to print the class you must use the object:

print(type(self.graphicsWidget))

Output:

<class '__main__.First'>

To identify that an object is of a class (or its parent classes) you can use the following methods, for example if it is a QWidget:

1.

if isinstance(obj, QtWidgets.QWidget):
    print("is QWidget")

2. If it's a QObject

2.1

if qobject.inherits("QWidget"):
    print("is QWidget")

2.2

if qobject.isWidgetType():
    print("is QWidget")

Upvotes: 3

Jussi Nurminen
Jussi Nurminen

Reputation: 2408

The First() instance is also an instance of QtWidgets.QGraphicsView precisely because you said so, i.e. you made the class inherit from QtWidgets.QGraphicsView. You can check this:

f = First()
isinstance(f, QtWidgets.QGraphicsView)  # True

Since QtWidgets.QGraphicsViewin turn inherits from QtWidgets.QWidget, the following is also True:

isinstance(f, PyQt5.QtWidgets.QWidget)

Thus, addWidget happily accepts the instance as a QWidget. (Note that addWidget does not have to do explicit type checking on the instance it receives. The code could work solely due to the fact that the instance "quacks like a duck", i.e. it has the appropriate QWidget methods).

Upvotes: 1

Related Questions