如何在 Qt/C++/QML 中实现类似 WPF 的 MVVM?
Posted
技术标签:
【中文标题】如何在 Qt/C++/QML 中实现类似 WPF 的 MVVM?【英文标题】:How to implement WPF-like MVVM in Qt/C++/QML? 【发布时间】:2013-09-06 01:00:21 【问题描述】:我正在编写一个概念验证应用程序,这非常简单。基本上它由一个 UI 组成,其中在 QML ListView 中显示“Note”类型对象的列表。
然后我有几个类是类似的东西:
#ifndef NOTE_H
#define NOTE_H
#include <string>
using namespace std;
class Note
public:
Note(QObject* parent = 0)
: QObject(parent)
Note(const int id, const string& text)
: _id(id), _text(text)
int id()
return _id;
const string text()
return _text;
void setText(string newText)
_text = newText;
private:
int _id;
string _text;
;
#endif // NOTE_H
然后是一个存储库:
class NoteRepository : public Repository<Note>
public:
NoteRepository();
~NoteRepository();
virtual shared_ptr<Note> getOne(const int id);
virtual const unique_ptr<vector<Note>> getAll();
virtual void add(shared_ptr<Note> item);
private:
map<int, shared_ptr<Note>> _cachedObjects;
;
最后是一个向 QML 公开 Note 的 ViewModel
class MainViewModel : public QObject
Q_OBJECT
Q_PROPERTY(QQmlListProperty<Note> notes READ notes NOTIFY notesChanged)
Q_PROPERTY(int count READ count() NOTIFY countChanged)
public:
MainViewModel(QObject *newParent = 0);
int count();
QQmlListProperty<Note> notes();
signals:
void notesChanged();
void countChanged();
public slots:
private:
std::shared_ptr<UnitOfWork> _unitOfWork;
static void appendNote(QQmlListProperty<Note> *list, Note *note);
QList<Note*> _notes;
;
请不要介意这里有任何 C++ 错误,并注意它们是不完整的,这不是此刻的重点,因为我会在学习的过程中不断调整这一点。
我苦苦挣扎的一点是,如何将类似列表的对象公开给 QML?要求是此列表必须是动态的,应该能够添加、删除和修改注释的文本。当列表被 C++ 修改时,它也应该通知 UI(信号)。
我尝试了 QQmlListProperty,但无法找到将其公开给 QML 的方法。然后我阅读了另一篇 SO 帖子,这种类型不能被 QML 修改(??),我偶然发现了 QAbstractItemModel。
无论如何,谁能指出我正确的方向?
【问题讨论】:
QAbstractItemModel
应该是正确的方向。你可以在这里找到更多信息:qt-project.org/doc/qt-5.1/qtquick/…
【参考方案1】:
我在another answer 中发布了一个相当完整的示例。
一般程序是:
创建一个派生自 QAbstractItemModel
的模型。您可以重用 Qt 已经提供的任何模型,例如 QStringListModel
。
将其暴露给 QML。例如。使用 QML Engine 的 rootContext()
的 setContextProperty()
。
模型的角色在 QML 的委托上下文中是可见的。 Qt 在roleNames()
的默认实现中为DisplayRole
(display
) 和EditRole
(edit
) 提供了名称和角色之间的默认映射。
delegate: Component
TextInput
width: view.width // assuming that view is the id of the view object
text: edit // "edit" role of the model, to break the binding loop
onTextChanged: model.display = text // "display" role of the model
如果需要,您可以通过在视图和后端模型之间附加代理模型来创建中间视图模型。您可以从 QAbstractProxyModel
或其子类之一派生。
【讨论】:
【参考方案2】:除了一个细节之外,接受的答案是正确的。在 MVVM 中,您会将 ViewModel 暴露给 QML,而不是 Model。
【讨论】:
以上是关于如何在 Qt/C++/QML 中实现类似 WPF 的 MVVM?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Python 和 Qt Quick QML 应用程序中实现简化的双向数据绑定