来自不同组件的 QML findChild [英] QML findChild from a different component
问题描述
目标:我正在为嵌套样本的基于 Matplotlib 的库编写 Gui 前端(pip install anesthetic
如果你想看一看).
The objective:
I'm writing a Gui front-end for a Matplotlib-based library for nested samples (pip install anesthetic
if you want to have a look).
我将如何在 C++ 中进行操作:我之前使用 QML 的经验是一个 C++
程序,而不是进入 QML 寻找要渲染的画布,我创建了一个 C++ 对象,在 QML 的类型系统中注册了它,并让它作为 QtQuick 控件小部件运行.据我所知,这是推荐的做事方式:在 QML 中完成所有渲染,在 C++ 中完成所有业务端逻辑.
How I would go about it in C++: My previous experience with QML was a C++
program, where instead of going into QML to find a canvas to render to, I created a C++ object, registered it in QML's type system, and had it behave as a QtQuick controls widget. As far as I know this is the recommended way of doing things: have all the rendering be done in QML, and have all the business-end-logic in C++.
最好的方法以及为什么我不能这样做:这种方法在这里不起作用.AFAIK 你只能使用 C++ 实现自定义 QML,我需要程序是纯 Python(为了其他人能够维护它)一些 JS 是可访问的,QML 很容易理解和编辑,所以我没有反对意见(C++ 很难拒绝).
THe best approach and why I can't do it: This approach doesn't work here. AFAIK you can only implement custom QML using C++, and I need for the program to be pure-ish Python (for others to be able to maintain it) some JS is accessible and QML is pretty easy to understand and edit, so I had no objections (C++ was a hard no).
我的工作:我有我想要的工作实现.这一切都在一个文件中.所以,很自然地,我想将要绘制到的画布拆分为一个单独的文件:figure.qml
.问题是,每当从单独的文件中加载对象时,我似乎都找不到该名称的对象(下一步是使用 Loader
,因为 Figure
是相当笨重).
what I got working: I have a working implementation of what I want. It was all in one file. So, naturally I wanted to split the canvas to which I'm drawing to into a separate file: figure.qml
. Trouble is, I can't seem to find the object by that name whenever it's loaded from a separate file (the next step is to use a Loader
, because the Figure
is quite clunky).
我有一个两文件项目,view.qml
是根目录,Figure.qml
中有一个组件.问题是,它仅适用于我在 view.qml
中使用 objectName: "component"
而不是在 Component.qml
中加载的东西.
I have a two-file project with view.qml
being the root, and a component in Figure.qml
.
The trouble is, it only works if I load the thing with objectName: "component"
in view.qml
and not in Component.qml
.
那么 Pyside
中的一个 findChild
是如何用于不同 .qml
文件中的 objectName 的?
So how does one findChild
in Pyside
for an objectName that's in a different .qml
file?
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 {
}
}
图.qml
import QtQuick.Controls 2.12
import QtQuick 2.12
Component{
Rectangle{
objectName: "figure"
}
}
推荐答案
Component
用于定义 QML 元素,它不实例化,因此您无法访问该对象.创建一个 Figure.qml 就相当于创建了一个 Component,而你是在另一个 Component 内部创建了一个 Component.
Component
is used to define a QML element, it does not instantiate it, therefore you cannot access the object. Creating a Figure.qml is equivalent to creating a Component, and you are creating a Component inside another Component.
解决方案是不使用组件:
The solution is not to use Component:
图.qml
import QtQuick.Controls 2.12
import QtQuick 2.12
Rectangle{
objectName: "figure"
}
但是不建议使用 objectName 因为例如,如果您创建多个组件,您将如何识别它是哪个组件?o 如果您在时间 T 之后创建对象,或者使用 Loader 或 Repeater,您将无法应用该逻辑.最好创建一个允许获取这些对象的 QObject 来代替它们:
But it is not recommended to use objectName since, for example, if you create multiple components, how will you identify which component it is? o If you create the object after a time T, or use Loader or Repeater you will not be able to apply that logic. Instead of them it is better to create a QObject that allows obtaining those objects:
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)
}
这篇关于来自不同组件的 QML findChild的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!