基本上我的情况是这样的:
我有一个扩展QQuickView的类,它通过设置上下文属性将某些对象从C ++暴露给QML。显示的视图是从QML创建的,并且是同一个自定义组件的所有不同的结构;在发生某些事件时会创建新视图,当发生这种情况时,现有视图应显示最初在C ++端分配给它们的对象,而新视图应显示分配给它们的内容。
所以,在C ++方面,我有类似的东西:
WindowManager::WindowManager(QQuickView *parent) :
QQuickView(parent)
{
// Setting the source file to use
this->setSource(QUrl("qrc:/qml/main.qml"));
// Exposing the istance of this class to QML for later use
this->rootContext()->setContextProperty("qquickView", this);
// Calling the method that will create dynamically a new view that will be child of main.qml; the parameter is not important, just a random number to start with
this->prepareNewView(3)
this->showFullScreen();
}
WindowManager::prepareNewView(int stuffId)
{
MyDatabase db;
// Getting something to show in QML from somewhere based on the parameter received
SomeStuff stuff = db.getStuff(stuffId)
// Exposing the object I need to show in QML
this->rootContext()->setContextProperty("someStuff", stuff);
QObject *object = this->rootObject();
// Here I'm invoking a function from main.qml that will add a new view dynamically
QMetaObject::invokeMethod(object, "addView");
}
现在,在QML方面,我有一个这样的主文件:
// main.qml
Rectangle {
id: mainWindow
width: 1000
height: 1000
// This function adds a component to mainWindow
function addView()
{
// Creating the component from my custom made component
var component = Qt.createComponent("MyComponent.qml");
// Creating an istance of that component as a child of mainWindow
var newView = component.createObject(mainWindow);
// ... Now I would be doing something with this new view, like connecting signals to slots and such
}
}
然后我有了自定义组件,这是将动态创建的视图:
// MyComponent.qml
Rectangle {
id: customComponent
// Here I would be using the object I exposed from the C++ side
x: someStuff.x
y: someStuff.y
width: someStuff.width
height: someStuff.height
// Here I'm creating a MouseArea so that clicking this component will cause the creation of another view, that will have to show diffrent things since the parameter I'm passing should be different from the starting parameter passed in the constructor of WindowManager
MouseArea {
anchors.fill: parent
onClicked: qquickView.prepareNewView(Math.random())
}
}
现在,随着它的一切,它首先会显示id为3的“东西”,它被公开为主要上下文的上下文属性。
但是,如果我单击MouseArea,假设将传递3以外的id,将公开具有相同名称的新上下文属性,从而导致覆盖旧属性。这意味着第一个视图现在将显示刚刚暴露的“东西”,而不是基于stuffId的“东西”等于3,而我需要的是第一个继续显示它应该显示的视图(“东西” “id = 3),以及任何其他视图,稍后会出现与其ID相对应的内容。
这是因为我在上下文中定义了每个组件共有的属性,而我应该定义一个只能由动态创建的组件的新等特性可见的属性。但是我该怎么做?
在文档中,我读到可以直接从C ++创建一个组件并定义它应该使用的上下文......类似这样的内容(摘自here):
QQmlEngine engine;
QStringListModel modelData;
QQmlContext *context = new QQmlContext(engine.rootContext());
context->setContextProperty("myModel", &modelData);
QQmlComponent component(&engine);
component.setData("import QtQuick 2.0\nListView { model: myModel }", QUrl());
QObject *window = component.create(context);
我认为这对我打算做的事情有用。每当我从C ++创建一个新视图(由鼠标区域上的点击引起)时,我创建一个以“someStuff”为属性的新上下文,这样每个视图都有自己的“东西”......但是我需要访问来自QML的新创建的视图,因为我在main.qml中的addView()函数中创建它之后我访问视图以便做某些细分(不重要的是什么),如果我从C ++创建组件的istance我不知道如何从QML访问它...有没有办法将组件从C ++传递到QML才能访问它?
我没有关于如何解决这个问题的想法,或者找到另一种方法来动态创建具有自定义内容的视图同时可见...任何建议都表示赞赏。
答案 0 :(得分:5)
我实际上发现直接将用C ++创建的组件传递给QML是可能的(并且很容易)。
所以现在,我修改了代码,就像这样:
WindowManager::prepareNewView(int stuffId)
{
MyDatabase db;
// Getting something to show in QML from somewhere based on the parameter received
SomeStuff stuff = db.getStuff(stuffId)
// Creating the new context, based on the global one
QQmlContext *context = new QQmlContext(this->rootContext());
// Exposing the object I need to show in QML to the new context
context ->setContextProperty("someStuff", stuff);
// Creating the component
QQmlComponent component(this->engine(), QUrl("qrc:/qml/MyComponent.qml"));
// Creating the istance of the new component using the new context
QQuickItem *newView = qobject_cast<QQuickItem*>(component.create(context));
// Getting the root component (the Rectangle with it mainWindow)
QObject *object = this->rootObject();
// Manually setting the new component as a child of mainWIndow
newView->setParentItem(qobject_cast<QQuickItem*>(object));
// Invoking the QML that will connect the events of the new window, while passing the component created above as QVariant
QMetaObject::invokeMethod(object, "addView", Q_ARG(QVariant, QVariant::fromValue(newView)));
}
在QML中,main.qml中的函数现在是这样的:
// Function called from C++; the param "newView" is the last component added
function addView(newView)
{
// ... Here I would use the new view to connect signals to slots and such as if I created "newView" directly in QML
}
所以我设法不要过多地改变代码。
答案 1 :(得分:2)
我认为您可以通过将对象设置为上下文属性来传递组件实例(QObject),就像在代码中一样。
class ViewInstance : public QObject
{
Q_OBJECT
public:
Q_INVOKABLE QObject* getCurrentViewInstance() {
...
QObject *window = component.create(context);
return window;
}
};
int main(int argc, char *argv[]) {
...
QQuickView view;
ViewInstance data;
view.rootContext()->setContextProperty("viewInstance", &data);
}
然后,在qml中,您可以通过调用viewInstance.getCurrentViewInstance()来获取组件实例。希望这会有所帮助。