QML findChild из другого компонента - PullRequest
1 голос
/ 21 июня 2020

Цель : я пишу Gui интерфейс для библиотеки на основе Matplotlib для вложенных образцов (pip install anesthetic, если хотите посмотреть).

Как я мог бы go об этом в C ++ : Мой предыдущий опыт работы с QML был программой C++, где вместо того, чтобы заходить в QML, чтобы найти холст для рендеринга, я создал объект C ++, зарегистрировал его в системе типов QML и заставил его вести себя как виджет управления QtQuick. Насколько я знаю, это рекомендуемый способ сделать что-то: сделать все рендеринг в QML и иметь все бизнес-end-logi c на C ++.

Лучший подход и почему я не могу этого сделать : Этот подход здесь не работает. AFAIK вы можете реализовать только собственный QML с помощью C ++, и мне нужно, чтобы программа была чистой-i sh Python (чтобы другие могли ее поддерживать), некоторые JS доступны, а QML довольно легко понять и редактировать, поэтому у меня не было возражений (С ++ был жестким нет).

что у меня работает : У меня есть рабочая реализация того, что я хочу. Все было в одном файле. Итак, естественно, я хотел разделить холст, на который я рисую, в отдельный файл: figure.qml. Проблема в том, что я не могу найти объект с таким именем всякий раз, когда он загружается из отдельного файла (следующий шаг - использовать Loader, потому что Figure довольно неуклюжий).

У меня есть двухфайловый проект, где view.qml - это root, а компонент - Figure.qml. Проблема в том, что это работает, только если я загружаю вещь с objectName: "component" в view.qml, а не с Component.qml.

Так как же один findChild в Pyside для objectName, который находится в другой .qml файл?

MWE:

main.py

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

view.qml

import QtQuick.Controls 2.12
import QtQuick.Windows 2.12

ApplicationWindow{
   Figure {

   }
}

Figure.qml

import QtQuick.Controls 2.12 
import QtQuick 2.12

Component{
  Rectangle{ 
    objectName: "figure"
  }
}

1 Ответ

2 голосов
/ 21 июня 2020

Component используется для определения элемента QML, он не создает его , поэтому вы не можете получить доступ к объекту. Создание Figure.qml эквивалентно созданию Компонента, и вы создаете Компонент внутри другого Компонента.

Решение состоит в том, чтобы не использовать Компонент:

Figure.qml

import QtQuick.Controls 2.12 
import QtQuick 2.12

Rectangle{ 
    objectName: "figure"
}

Но не рекомендуется использовать objectName, поскольку, например, если вы создаете несколько компонентов, как вы определите, какой это компонент? o Если вы создадите объект по истечении времени T или используете загрузчик или повторитель, вы не сможете применить этот лог c. Вместо них лучше создать 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)
}
...