現在在我的C++/QML應用,即使每個QML視圖只使用所有可用屬性的子集,所有的人都通過QDeclarativeContext::setContextProperty
在QDeclarativeView
的QDeclarativeEngine
顯示的根上下文暴露QML文件 - 這很醜陋。使用QDeclarativeContext層次與QDeclarativeView
Additional data that should only be available to a subset of component instances should be added to sub-contexts parented to the root context.
所以我想這樣做。但是,我還沒有找到進一步的文檔或信息如何實際使用子上下文。不幸的是,僅僅創建一個新的子上下文是不夠的。
實施例:
我有一個很簡單的QML文件
import QtQuick 1.0
Rectangle {
visible: true
width: 800
height: 600
Text {
text: message.text
anchors.centerIn: parent
}
}
訪問稱爲message
上下文屬性,該屬性被設爲一個QDeclarativeView的發動機的根上下文的子上下文內在main
:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget widget{nullptr, Qt::FramelessWindowHint};
widget.resize(800, 600);
MessageHolder message{"Hello World"};
// ceeate the new context and add the message to context properties
QDeclarativeContext message_context{view.engine()};
message_context.setContextProperty("message", &message);
// what needs to go here so that the new context is actually used?
view.setSource(QUrl{"path/to/main.qml"});
view.show();
widget.show();
return app.exec();
}
上面使用的MessageHolder
是一個簡單的類,它只是提供交流它被設置在建設這樣一個對象的onstant的QString:
class MessageHolder : public QObject {
Q_OBJECT
Q_PROPERTY(QString text READ text CONSTANT)
public:
MessageHolder(QString text);
QString text();
private:
QString _text;
};
正如上面已經指出,這種遺憾的是不工作,QML發出警告
/path/to/main.qml:9: ReferenceError: Can't find variable: message`
如果我不是message
屬性添加到根上下文一切工作正常。在創建環境和設置視圖的來源以使其工作之間,我需要做些什麼?
更深入的我真正想要做
在我的應用程序使用MVVM架構,其中每個QML視圖都有一個對應的C++視圖模型(在MVVM,而不是意識的解釋Qt術語)。
在任何給定時刻只有激活很多不同的ViewModels的一個,但是所有這些應用程序的啓動過程中實例化,然後通過上下文屬性暴露給QML。
最核心的問題我有,這是爲每個的ViewModels的唯一名稱的需要,從而也強烈耦合QML意見單一視圖模型。改爲使用名稱爲viewmodel
的單個通用上下文屬性會更好。
但是,這裏是問題:當一個新的視圖模型變爲活動狀態時,我必須在更改QML視圖之前或之後將viewmodel
context屬性重新設置爲新的viewmodel。但更改上下文屬性會導致重新評估當前活動的所有綁定。因此,當我第一次更改上下文屬性,然後認爲,舊視圖會嘗試更新,即使新的視圖模型不具備所需的性能,如果我第一次更改視圖,然後選擇上下文屬性的新視圖將在加載時評估其所有綁定,但由於上下文屬性尚未更新,所以必要的屬性尚不可用。
視覺上這不是一個問題,因爲在第一種情況下打破現在的觀點是要被卸載反正在第二種情況下,一旦新的上下文屬性設置新的視圖會立即重新評估所有屬性。儘管如此,在任何一種情況下,QML都會因爲缺少屬性而發出警告,這首先不好,因爲它混亂了日誌文件;其次,因爲我通過Q_ASSERT
將警告視爲調試版本中的致命錯誤,以便發現QML視圖中的錯誤或視覺模型在我的持續集成系統的早期沒有人工檢查。
但後來我在Qt documentation遇到下列事實跌跌撞撞:
While QML objects instantiated in a context are not strictly owned by that context, their bindings are. If a context is destroyed, the property bindings of outstanding QML objects will stop evaluating.
這正是我需要的,以便從垂死的觀點重新評估現在是無效的綁定停止QML。因此,我想在子上下文中設置viewmodel
上下文屬性,我將在視圖更改時銷燬並重新創建。
我相信我缺乏QDeclarativeView,QDeclarativeEngine和QDeclarativeContext一起工作的背景,因此無法追隨你的培養目標。你可能可以修改我的簡單例子來使用'contextForObject',使message屬性正確地暴露給QML文件嗎? – Corristo
關於你的最後一段:不必爲每個視圖模型設置獨特的名稱和設置上下文屬性,這正是我**不想再做的事情。負責視圖排序的Controller類已經知道下一個要加載哪個QML以及哪個視圖模型對應於它,所以重新設置一個通用的'viewmodel'上下文屬性對我來說似乎是合理的。 – Corristo
關於倒數第二段:由QML擁有的對象的對象銷燬可能不是立即的,但有一個'std :: unique_ptr'將子上下文作爲C++類中的成員保存。 –
Corristo