Sam Thadon
Sam Thadon

Reputation: 11

QQuickView not appearing in .ui GUI

Currently working on a Python program that uses Qt Widgets from an .ui file to display an interactable GUI. However, i have not found a way to integrate the QQuickview widget to display any QML code, which i have read is possible.

I'm using PySide2 to convert the .ui file from Qt Designer and have both attempted to use the QQuickWidget found in Qt Designer, and manualy adding a QQuickView to the gridLayout in the .ui to no success.

The QQuickWidget i added in Qt Designer was, as far as i could tell transformed to a QWidget when run in python, so setSource(QUrl) or .load(QUrl) Made no sense when running the code.

My attempt at adding the QQuickView:

    def connect_map_click(self):
        # Function for handling the connect map button
        engine = QQuickView()
        ctx = engine.rootContext()
        url = QUrl.fromLocalFile('QMLtest.qml')
        engine.setSource(url)
        container = QWidget.createWindowContainer(engine, self)
        container.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        engine.show()
        self.window.grd_map.addWidget(container, 0, 0)

The QML file:

import QtQuick 2.7
Rectangle {
    id: rectangle
    color: "red"
    width: 200
    height: 200
    visible: true
    Text {
        id:text
        text: "It's working!"
    }
}

I'm attempting to run the qml window on the right side of the screen, shown below. GUI where i'm attempting to add the QQuickView

Upvotes: 0

Views: 758

Answers (2)

eyllanesc
eyllanesc

Reputation: 244003

Explanation:

QQuickView is a local variable that will be deleted when "connect_map_click" is finished executing nothing in the container.

Solution:

The solution is to extend the life cycle and for this there are the following alternatives:

  1. Pass the QWindow associated with the window as parent:
def connect_map_click(self):
    engine = QQuickView(self.window.grd_map.parentWidget().window().windowHandle())
    # ...
  1. Make the QQuickView an attribute of another object that has a longer life cycle, for example the container:
# ...
container = QWidget.createWindowContainer(engine, self)
container.engine = engine
# ...

or the self:

def connect_map_click(self):
    # Function for handling the connect map button
    self.engine = QQuickView()
    ctx = self.engine.rootContext()
    url = QUrl.fromLocalFile('QMLtest.qml')
    self.engine.setSource(url)
    container = QWidget.createWindowContainer(self.engine, self)
    container.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
    engine.show()
    self.window.grd_map.addWidget(container, 0, 0)

Notes:

  • As you point out another solution is to use QQuickWidget since its life cycle depends on your parent who is self so he will live as long as the class. But QQuickWidget has limitations as the docs points out, including that you will not be able to record items that may be one of your requirements.

  • This behavior happens in PySide2 but in PyQt5 your initial code works since the container passes as parent to the QWindow of the window.

Upvotes: 0

Sam Thadon
Sam Thadon

Reputation: 11

Solved it myself as one tends to do right after asking for help.

Ended up finding out that i had not imported the QQuickWidget to the Python file before. So my solution ended up being to create a QQuickWidget in python, setting the source to the qml file and adding it to the grid in the .ui GUI.

    def connect_map_click(self):
        # Function for handling the connect map button

        qml_widget = QtQuickWidgets.QQuickWidget()
        qml_widget.setSource(QUrl('QMLtest.qml'))
        self.window.grd_map.addWidget(qml_widget)

resulting GUI: Working QML in GUI from .ui file

Upvotes: 0

Related Questions