首页 > 解决方案 > QML findChild 来自不同的组件

问题描述

目标:我正在为基于 Matplotlib 的嵌套样本库编写 Gui 前端(pip install anesthetic如果你想看看)。

我将如何在 C++ 中进行操作:我之前使用 QML 的经验是一个C++程序,我没有进入 QML 来寻找要渲染的画布,而是创建了一个 C++ 对象,在 QML 的类型系统中注册它,并让它表现得像QtQuick 控件小部件。据我所知,这是推荐的做事方式:所有渲染都在 QML 中完成,所有业务端逻辑都在 C++ 中。

最好的方法以及为什么我不能这样做:这种方法在这里不起作用。AFAIK,您只能使用 C++ 实现自定义 QML,我需要程序是纯 Python(以便其他人能够维护它)一些 JS 是可访问的,QML 很容易理解和编辑,所以我没有反对意见(C++ 很难拒绝)。

我得到了什么:我有一个我想要的工作实现。这一切都在一个文件中。所以,很自然地,我想将我正在绘制的画布拆分为一个单独的文件:figure.qml. 麻烦的是,每当从单独的文件中加载该对象时,我似乎都找不到该名称的对象(下一步是使用 a Loader,因为Figure它非常笨重)。

我有一个包含两个文件的项目,view.qml它是根目录,一个组件位于Figure.qml. 问题是,它只有在我用objectName: "component"inview.qml而不是 in加载东西时才有效Component.qml

那么如何使用另一个文件findChildPyside的 objectName.qml呢?

MWE:

主文件

import sys
from pathlib import Path
from matplotlib_backend_qtquick.backend_qtquickagg import FigureCanvasQtQuickAgg
from matplotlib_backend_qtquick.qt_compat import QtGui, QtQml, QtCore


def main():
    app = QtGui.QGuiApplication(sys.argv)
    engine = QtQml.QQmlApplicationEngine()
    displayBridge = DisplayBridge()
    context = engine.rootContext()                       
    qmlFile = Path(Path.cwd(), Path(__file__).parent, "view.qml")
    engine.load(QtCore.QUrl.fromLocalFile(str(qmlFile)))
    win = engine.rootObjects()[0]
    if win.findChild(QtCore.QObject, "figure"):
        print('success') # This fails
    app.exec_()

视图.qml

import QtQuick.Controls 2.12
import QtQuick.Windows 2.12

ApplicationWindow{
   Figure {

   }
}

图.qml

import QtQuick.Controls 2.12 
import QtQuick 2.12

Component{
  Rectangle{ 
    objectName: "figure"
  }
}

标签: pythonqmlpyside2

解决方案


Component用于定义QML 元素,它不会实例化它,因此您无法访问该对象。创建一个 Figure.qml 相当于创建一个 Component,而您是在另一个 Component 中创建一个 Component。

解决方案是不使用组件:

图.qml

import QtQuick.Controls 2.12 
import QtQuick 2.12

Rectangle{ 
    objectName: "figure"
}

但不建议使用 objectName,例如,如果您创建多个组件,您将如何识别它是哪个组件?o 如果您在时间 T 之后创建对象,或者使用 Loader 或 Repeater,您将无法应用该逻辑。最好创建一个允许获取这些对象的 QObject 来代替它们:

from PySide2 import QtCore
import shiboken2


class ObjectManager(QtCore.QObject):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._qobjects = []

    @property
    def qobjects(self):
        return self._qobjects

    @QtCore.Slot(QtCore.QObject)
    def add_qobject(self, obj):
        if obj is not None:
            obj.destroyed.connect(self._handle_destroyed)
            self.qobjects.append(obj)
        print(self.qobjects)

    def _handle_destroyed(self):
        self._qobjects = [o for o in self.qobjects if shiboken2.isValid(o)]
# ...
object_manager = ObjectManager()
context = engine.rootContext()
context.setContextProperty("object_manager", object_manager)
qmlFile = Path(Path.cwd(), Path(__file__).parent, "view.qml")
engine.load(QtCore.QUrl.fromLocalFile(str(qmlFile)))
# ...
import QtQuick.Controls 2.12 
import QtQuick 2.12

Rectangle{ 
    Component.onCompleted: object_manager.add_qobject(this)
}

推荐阅读