SCP3008
SCP3008

Reputation: 145

QQmlApplicationEngine list index out of range issue

I am trying to run the last 2 examples from this website and end up with root = engine.rootObjects()[0] # type: QObject IndexError: list index out of range error for both examples (Signal connection for root layout) (Signal connection of other qml file)

If it helps, I put all the example files onto the same directory level and changed the import statements to Pyside6 (from PySide6.QtCore...) instead of PySide2. I also added my version of the code if it makes it easier to see:

main.py:

import sys

from PySide6.QtCore import *
from PySide6.QtQml import QQmlApplicationEngine
from PySide6.QtWidgets import QApplication


def say(s):
    print(s)


if __name__ == '__main__':
    app = QApplication()
    engine = QQmlApplicationEngine()
    engine.load(QUrl.fromLocalFile('main.qml'))
    # Get the root object.
    root = engine.rootObjects()[0]  # type: QObject
    # Find the target object. Since our target object is Window, which is the root object. So use it directly.
    target_view = root
    # Bind signal.
    target_view.say.connect(say)  # The former one is the signal of qml, and the latter one is from Python
    # say() method.
    
    sys.exit(app.exec())

main.qml:

import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Window 2.12

Window {
    visible: true
    width: 600; height: 400

    signal say(string s)

    Button {
        text: "hello"
        onClicked: say(text)
    }
}

Upvotes: 0

Views: 1050

Answers (1)

eyllanesc
eyllanesc

Reputation: 244252

Possible causes of the error are:

  • The path of the .qml is incorrect so the .qml is not loaded.
  • The loading of the .qml is not synchronous as you are assuming.
  • The .qml has some error (syntax for example)

Considering the above, the solution is:

import os
import sys
from pathlib import Path

from PySide6.QtCore import QCoreApplication, Qt, QUrl
from PySide6.QtQml import QQmlApplicationEngine
from PySide6.QtWidgets import QApplication

CURRENT_DIRECTORY = Path(__file__).resolve().parent


def say(s):
    print(s)


if __name__ == "__main__":
    app = QApplication()
    engine = QQmlApplicationEngine()
    filename = os.fspath(CURRENT_DIRECTORY / "main.qml")
    url = QUrl.fromLocalFile(filename)

    def handle_object_created(obj, obj_url):
        if obj is None and url == obj_url:
            QCoreApplication.exit(-1)
        else:
            root = engine.rootObjects()[0]
            target_view = root
            target_view.say.connect(say)

    engine.objectCreated.connect(handle_object_created, Qt.QueuedConnection)
    engine.load(url)

    sys.exit(app.exec())

But anyway I don't prefer to use rootObjects but instead export a QObject:

import os
import sys
from pathlib import Path

from PySide6.QtCore import QCoreApplication, QObject, Qt, QUrl, Signal
from PySide6.QtQml import QQmlApplicationEngine
from PySide6.QtWidgets import QApplication

CURRENT_DIRECTORY = Path(__file__).resolve().parent


class Helper(QObject):
    say = Signal(str)


def say(s):
    print(s)


if __name__ == "__main__":
    app = QApplication()
    engine = QQmlApplicationEngine()

    helper = Helper()
    helper.say.connect(say)

    engine.rootContext().setContextProperty("helper", helper)

    filename = os.fspath(CURRENT_DIRECTORY / "main.qml")
    url = QUrl.fromLocalFile(filename)

    def handle_object_created(obj, obj_url):
        if obj is None and url == obj_url:
            QCoreApplication.exit(-1)

    engine.objectCreated.connect(handle_object_created, Qt.QueuedConnection)
    engine.load(url)

    sys.exit(app.exec())
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Window 2.12

Window {
    visible: true
    width: 600
    height: 400

    Button {
        text: "hello"
        onClicked: helper.say(text)
    }

}

Upvotes: 1

Related Questions