3

I have the following code:

from PyQt5 import QtWebEngineWidgets, QtWidgets


class Q(QtWebEngineWidgets.QWebEnginePage):
    pass


app = QtWidgets.QApplication([])

l = QtWebEngineWidgets.QWebEngineView()
print(type(l.page()))

l.setPage(Q(l))
print(type(l.page()))

p = Q()
l.setPage(p)
print(type(l.page()))

l.setPage(Q())
print(type(l.page()))

app.exec_()

And here's the output:

<class 'PyQt5.QtWebEngineWidgets.QWebEnginePage'>
<class '__main__.Q'>
<class '__main__.Q'>
<class 'PyQt5.QtWebEngineWidgets.QWebEnginePage'>

First I create a new instance of the QWebEnginePage-derived Q-class, set the view as its parent and assign it as the view's page. It works as expected.

Next I do the same, but without giving the parent. Instead, I create a temporary variable that holds a new Q and assign it. It still works as expected.

Finally, I directly assign a dynamically created parentless Q. For some reason this doesn't work and the page resets to the default class.

Why does this happen?

ekhumoro
  • 115,249
  • 20
  • 229
  • 336
Dariush
  • 463
  • 3
  • 12

1 Answers1

1

The QWebEngineView does not take ownership of the QWebEnginePage, and it does not re-parent it.

For the third example, the page has no parent, but it's kept alive because python holds a global reference to it.

For the last example, there is no parent and no external reference, so the page gets garbage-collected before it is set. It is effectively equivalent to calling setPage(None), which will remove the previously set page and restore the default.

ekhumoro
  • 115,249
  • 20
  • 229
  • 336
  • Why does the reference necessarily have to be external? I can create a normal Python object that is referenced only from inside another object and it doesn't get deleted, so why is PyQt different? Is it intentional or does it store references in some different way that doesn't prevent them from being trashed? – Dariush Nov 06 '16 at 19:35
  • @Dariush. As I said: the view does not take ownership and does not re-parent, so it's up to the caller to keep a reference. Qt is a C++ library and knows nothing about Python, so PyQt has to play by its rules. PyQt is quite a thin wrapper around Qt, so you will have to get used to dealing with C++ ways of dealing with things from time to time. This just goes to show how pampered we normally are as Python coders: it hides *a lot* of the ugly details. (PS: the Qt docs will always state who has ownership wherever it's relevant). – ekhumoro Nov 06 '16 at 20:13
  • So, PyQt does some sort of manual garbage collection to imitate C++ behavior? If yes - how? And why - purely for compatibility with Qt on C++? – Dariush Nov 06 '16 at 20:34
  • No, as I said: it's a *thin* wrapper and plays by Qt rules. All it does is marshall arguments between Python and C++. It's just a translation layer. It does not implement anything. – ekhumoro Nov 06 '16 at 20:47
  • PS: the PyQt bindings are generated by [SIP](http://pyqt.sourceforge.net/Docs/sip4/introduction.html). – ekhumoro Nov 06 '16 at 20:51
  • Oh, got it. Thanks for the explanation. :) – Dariush Nov 06 '16 at 20:57