Model View Options In Qt
This article may require cleanup to meet the Qt Wiki's quality standards. Reason: Auto-imported from ExpressionEngine. Please improve this article if you can. Remove the {{cleanup}} tag and add this page to Updated pages list after it's clean. |
[toc align_right="yes" depth="2"]
Model - View Options in Qt
The Model – View architecture is one of most popular ways to separate data and presentation in a software design. It is a special case of the Model – View – Controller architecture where the View and Controller objects are combined.
The Model – View architecture serves several purposes. It increases code reuse (because the model does not change when someone wants a new view), it increases code quality (again because the highly-tested model is not touched when a view changes), and it generally increases the sanity level of a project by breaking it down into more manageable pieces.
There’s one more benefit to the Model – View architecture which today’s development landscape makes increasingly relevant – it promotes specialization within a project. In “the old days” (something like two or three years ago) this specialization may have been subtle – only the most experienced coders were trusted to work on the model while junior team members proved themselves working on views.
Today’s teams are often more explicitly specialized, with designers and user experience specialists working on the system’s interactions with humans, while software engineers focus on core functionality. Qt allows different specialists to work in different languages, so for example a web designer can work in HTML, JavaScript, and CSS while interacting with a model coded in C++ using the Qt framework.
The Qt framework offers three primary ways to implement a Model – View architecture. In each case the model is implemented using Qt C++ objects. However, the views can be implemented in C+, in HTML using Qt WebKit, or using the new QML declarative language.
Pure C+
This is the starting point. Everything is done in C+; you just need to consciously separate model from view. The Model Classes article gives details on creating the model.
Implementing the view
This is easy to think about, too. Qt 4 introduced a set of item view classes that use the model - view architecture. The Model/View Programming article provides a detailed treatment of the architecture as coded in a pure C+ Qt implementation.
Communicating between model and view
Because this is pure Qt C+, communication is done using standard Qt signals and slots.
Hybrid Qt – WebKit
Using the QtWebkit module, it is possible to implement views using HTML, JavaScript, and CSS. This is commonly called a Qt Hybrid implementation, and it allows web developers with little or no C+ experience to implement views. The Server-driven UI with Hybrid Qt - WebKit Integration wiki article gives more details.
Implementing the view
Build the view in HTML, JavaScript, and CSS, just like you would when implementing MVC in a pure web environment. It is theoretically possible to implement an MVC architecture purely in JavaScript, but that would eliminate much of the value of the hybrid approach.
More typically the model will be built in Qt C+, with interfaces from the QObjects exposed to the web environment using the QWebFrame::addToJavaScriptWindowObject function. The interfaces are not available by default for security reasons as the C+ objects may execute outside of the sandbox of the web environment.
Again, thinking in theoretical terms, there's no reason the model could no be implemented in a combination of JavaScript and C+. This may have appeal where there already exists substantial business logic coded in JavaScript.
Communicating between model and (C) view
- Qt C+ signals, slots, and properties in the model can be exposed to web-based views.
- Qt properties are accessible as JavaScript properties.
- Qt slots are accessible as JavaScript functions.
- Qt signals can be connected to a variety of JavaScript mechanisms, including for example triggering a JavaScript handler that responds to a Qt C++ signal that the albums have changed. More details are provided in Using Signals and Slots in the online documentation.
For example, here is a snippet of the code for a music library object. Notice the signal that albums have been changed and the use of QVariant and QVariantList to pass data between the native and web environments.
class MusicLibrary : public QObject
{
Q_OBJECT
Q_PROPERTY(QVariantList allAlbums READ allAlbums)
public:
MusicLibrary (QObject* parent = NULL);
QVariantList allAlbums() const;
public slots:
QVariant addSong(const QVariant &);
QVariant addAlbum(const QVariant &);
signals:
void albumsChanged();
private:
QMap<QUuid,Song> song_map;
QMap<QUuid,Album> album_map;
};
class MediaCenter : public QObject
{
Q_OBJECT
public:
MediaCenter(QObject* o = NULL);
MusicManager &amp; music() { return '''musicManager; }
private:
MusicManager''' musicManager;
};
Here is how you connect the Qt signal to the JavaScript’s refresh function to update the view when an album changes:
musicManager.albumsChanged.connect(refresh);
Qt Quick
Qt Quick introduces QML, a language that allows you to declaratively build an object tree of QML elements. QML improves the integration between JavaScript and Qt's existing QObject based type system, adds support for automatic property bindings and provides network transparency at the language level.
Qt Quick is well suited for building great-looking, dynamic views. Models can be built using C++ or directly in QML for some model types.
Build the view
Qt widgets can create views into models that are exposed using the QAbstractItemModel interface. This interface is also supported by QML.
To expose a QAbstractItemModel to QML a context property is used:
QAbstractItemModel *model = …;
context->setContextProperty("dataModel", model);
QML currently provides three elements devoted to creating views into models. The ListView and GridView elements create list and grid views respectively. The PathView element lays out model-provided items on a path, for example a loop path that allows you to create a carousel interface into a list.
Regardless of the view element employed, the context property set to the data model is bound to the model property of a view element.
ListView {
model: contactModel
delegate: delegate
highlight: highlight
}
Communicating between model and view
All QML code executes within a context. The context keeps track of what data is available to different leaves and nodes in a QML object tree. Data is shared as context properties or context objects. A context property is simply a way to expose a given QObject through a given name. For example, to expose a QColor property named frameColor to QML, simply use the following snippet:
QDeclarativeContext *context = …;
context->setContextProperty("frameColor", QColor(Qt::red));
This property can then be accessed from within the QML context as a global property, as shown below. Remember property values are bound, not assigned, in QML. This means you can alter the frameColor property from C++ and the change will be reflected in QML.
Rectangle {
border.color: frameColor
}