QQmlApplicationEngine 列表索引超出范围问题

Posted

技术标签:

【中文标题】QQmlApplicationEngine 列表索引超出范围问题【英文标题】:QQmlApplicationEngine list index out of range issue 【发布时间】:2021-06-29 13:57:21 【问题描述】:

我正在尝试运行此 website 中的最后两个示例并最终得到 root = engine.rootObjects()[0] # type: QObject IndexError: list index out of range 两个示例的错误(根布局的信号连接)(其他 qml 文件的信号连接)

如果有帮助,我将所有示例文件放在同一目录级别,并将导入语句更改为 Pyside6(来自 PySide6.QtCore...)而不是 PySide2。如果代码更易于查看,我还添加了我的代码版本:

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)
    

【问题讨论】:

通常这意味着您的 QML 代码存在问题,并且通常会打印出来。您在输出中看到任何错误吗?在任何情况下,您都应该在访问它之前检查 rootObjects() 是否返回空列表。在 C++ 中,处理错误的常用方法是连接到引擎的 objectCreated 信号并在对象为空时退出应用程序。不确定 Python 中的等价物是什么。 【参考方案1】:

错误的可能原因有:

.qml 的路径不正确,因此 .qml 未加载。 .qml 的加载并不像您假设的那样同步。 .qml 有一些错误(例如语法)

综合以上情况,解决办法是:

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())

但无论如何我不喜欢使用 rootObjects 而是导出一个 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)
    


【讨论】:

以上是关于QQmlApplicationEngine 列表索引超出范围问题的主要内容,如果未能解决你的问题,请参考以下文章

使用 QQmlApplicationEngine 强制 QApplication 处于前台

如何在使用 Qt.quit() 而不是整个 QGuiApplication 时只退出当前的 QQmlApplicationEngine?

falcor:使用路径中的索引来设置项目值

qml-main.cpp中的两种启动Qt Quick App模式

如何根据名称而不是索引来订购选择?

如何在 pandas Dataframe KeyError: False 中索引出数字的值