Restore QML/C++ extensions tutorial and fix plugin docs and examples

This restores the "Writing QML Extensions with C++" tutorial that
was removed during the recent QML doc restructure.

This also updates outdated docs in "Creating C++ Plugins for QML"
that referred to the use of Q_EXPORT_PLUGIN2() and such as the
process for writing QML plugins in Qt 5 has changed.

Note the plugins.json line was removed from
examples/qml/cppextensions/plugins/plugins.pro since this json file
was removed in a previous commit, as plugins no longer require the
empty json file.

Change-Id: I795d6faf6a741466a952feb8e15b028ec3d52b69
Reviewed-by: Chris Adams <christopher.adams@nokia.com>
This commit is contained in:
Bea Lam 2012-08-03 16:55:25 +10:00 committed by Qt by Nokia
parent 0cefbff3b4
commit c0c5890b3f
6 changed files with 520 additions and 30 deletions

View File

@ -7,8 +7,6 @@ TARGET = qmlqtimeexampleplugin
SOURCES += plugin.cpp
OTHER_FILES += "plugin.json"
qdeclarativesources.files += \
com/nokia/TimeExample/qmldir \
com/nokia/TimeExample/center.png \

View File

@ -43,6 +43,9 @@ from QML.
Additionally, the QtQml module provides mechanisms for implementing QML-specific
features such as \e{attached properties} and \e{default properties} in C++.
(Note that a number of the important concepts covered in this document are
demonstrated in the \l{Writing QML Extensions with C++} tutorial.)
\section1 Registering C++ types with the QML type system
@ -633,7 +636,10 @@ QtQuick C++ module. Therefore, this class should be subclassed when it is
necessary to implement a visual type in C++ that can be integrated into a
QML-based user interface.
See the QQuickItem documentation for more information.
See the QQuickItem documentation for more information. Additionally, the
\l{Writing QML Extensions with C++} tutorial demonstrates how a QQuickItem-based
visual item can be implemented in C++ and integrated into a QtQuick-based user
interface.
\section1 Receiving Notifications for Object Initialization

View File

@ -58,6 +58,9 @@ used in a way that requires the engine to access additional type information
property, or if one of its enum types is to be used in this way — then the
class may need to be registered.
(Note that a number of the important concepts covered in this document are
demonstrated in the \l{Writing QML Extensions with C++} tutorial.)
\section1 Properties

View File

@ -0,0 +1,482 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:FDL$
** GNU Free Documentation License
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms
** and conditions contained in a signed written agreement between you
** and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
\page qml-extending-tutorial-index.html tutorial
\title Writing QML Extensions with C++
\brief tutorial about extending QML with Qt C++
The QtQml C++ module provides a set of APIs for extending QML through
C++ extensions. You can write extensions to add your own QML types, extend existing
Qt types, or call C/C++ functions that are not accessible from ordinary QML code.
This tutorial shows how to write a QML extension using C++ that includes
core QML features, including properties, signals and bindings. It also shows how
extensions can be deployed through plugins.
You can find the source code for this tutorial in \c Qt's
examples/quick/tutorials/extending directory.
Tutorial chapters:
\list 1
\li \l{examples/tutorials/extending/chapter1-basics}{Creating a New Type}
\li \l{examples/tutorials/extending/chapter2-methods}{Connecting to C++ Methods and Signals}
\li \l{examples/tutorials/extending/chapter3-bindings}{Property Binding}
\li \l{examples/tutorials/extending/chapter4-customPropertyTypes}{Using Custom Property Types}
\li \l{examples/tutorials/extending/chapter5-listproperties}{Using List Property Types}
\li \l{examples/tutorials/extending/chapter6-plugins}{Writing an Extension Plugin}
\li \l{qml-extending-tutorial7.html}{In Summary}
\endlist
Many of the topics covered in this tutorial are documented in further detail in
\l {qtqml-cppintegration-topic.html}{Integrating QML and C++} and its documentation
sub-topics. In particular, you may be interested in the sub-topics
\l{qtqml-cppintegration-exposecppattributes.html}{Exposing Attributes of C++ Classes to QML}
and \l {qtqml-cppintegration-definetypes.html}{Defining QML Types from C++}.
*/
/*!
\title Chapter 1: Creating a New Type
\example examples/tutorials/extending/chapter1-basics
A common task when extending QML is to provide a new QML type that supports some
custom functionality beyond what is provided by the built-in \l {QML Types Provided by Qt Quick}{QtQuick types}.
For example, this could be done to implement particular data models, or provide
elements with custom painting and drawing capabilities, or access system features
like network programming that are not accessible through built-in QML features.
In this tutorial, we will show how to use the C++ classes in the Qt Declarative
module to extend QML. The end result will be a simple Pie Chart display implemented by
several custom QML types connected together through QML features like bindings and
signals, and made available to the QML runtime through a plugin.
To begin with, let's create a new QML type called "PieChart" that has two properties: a name
and a color. We will make it available in a \l {Modules}{module} called "Charts", with
a module version of 1.0.
We want this \c PieChart type to be usable from QML like this:
\code
import Charts 1.0
PieChart {
width: 100; height: 100
name: "A simple pie chart"
color: "red"
}
\endcode
To do this, we need a C++ class that encapsulates this \c PieChart type and its two
properties. Since QML makes extensive use of Qt's \l{Meta-Object System}{meta object system},
this new class must:
\list
\li Inherit from QObject
\li Declare its properties using the Q_PROPERTY macro
\endlist
Here is our \c PieChart class, defined in \c piechart.h:
\snippet examples/tutorials/extending/chapter1-basics/piechart.h 0
The class inherits from QQuickPaintedItem because we want to override
QQuickPaintedItem::paint() in perform drawing operations with the QPainter API.
If the class just represented some data type and was not an item that actually needed
to be displayed, it could simply inherit from QObject. Or, if we want to extend the
functionality of an existing QObject-based class, it could inherit from that class instead.
Alternatively, if we want to create a visual item that doesn't need to perform drawing
operations with the QPainter API, we can just subclass QQuickItem.
The \c PieChart class defines the two properties, \c name and \c color, with the Q_PROPERTY macro,
and overrides QQuickPaintedItem::paint(). The class implementation in \c piechart.cpp
simply sets and returns the \c m_name and \c m_color values as appropriate, and
implements \c paint() to draw a simple pie chart. It also turns off the
QGraphicsItem::ItemHasNoContents flag to enable painting:
\snippet examples/tutorials/extending/chapter1-basics/piechart.cpp 0
\dots 0
\snippet examples/tutorials/extending/chapter1-basics/piechart.cpp 1
Now that we have defined the \c PieChart type, we will use it from QML. The \c app.qml
file creates a \c PieChart item and display the pie chart's details
using a standard QML \l Text item:
\snippet examples/tutorials/extending/chapter1-basics/app.qml 0
Notice that although the color is specified as a string in QML, it is automatically
converted to a QColor object for the PieChart \c color property. Automatic conversions are
provided for various other \l {QML Basic Types}{basic types}; for example, a string
like "640x480" can be automatically converted to a QSize value.
We'll also create a C++ application that uses a QQuickView to run and
display \c app.qml. The application must register the \c PieChart type
using the qmlRegisterType() function, to allow it to be used from QML. If
you don't register the type, \c app.qml won't be able to create a \c PieChart.
Here is the application \c main.cpp:
\snippet examples/tutorials/extending/chapter1-basics/main.cpp 0
This call to qmlRegisterType() registers the \c PieChart type as a type called "PieChart", in a module named "Charts",
with a module version of 1.0.
Lastly, we write a \c .pro project file that includes the files and the \c declarative library:
\quotefile examples/tutorials/extending/chapter1-basics/chapter1-basics.pro
Now we can build and run the application:
\image extending-tutorial-chapter1.png
Try it yourself with the code in Qt's \c examples/tutorials/extending/chapter1-basics directory.
*/
/*!
\title Chapter 2: Connecting to C++ Methods and Signals
\example examples/tutorials/extending/chapter2-methods
Suppose we want \c PieChart to have a "clearChart()" method that erases the
chart and then emits a "chartCleared" signal. Our \c app.qml would be able
to call \c clearChart() and receive \c chartCleared() signals like this:
\snippet examples/tutorials/extending/chapter2-methods/app.qml 0
\image extending-tutorial-chapter2.png
To do this, we add a \c clearChart() method and a \c chartCleared() signal
to our C++ class:
\snippet examples/tutorials/extending/chapter2-methods/piechart.h 0
\dots
\snippet examples/tutorials/extending/chapter2-methods/piechart.h 1
\dots
\snippet examples/tutorials/extending/chapter2-methods/piechart.h 2
\dots
\snippet examples/tutorials/extending/chapter2-methods/piechart.h 3
The use of Q_INVOKABLE makes the \c clearChart() method available to the
Qt Meta-Object system, and in turn, to QML. Note that it could have
been declared as as a Qt slot instead of using Q_INVOKABLE, as
slots are also callable from QML. Both of these approaches are valid.
The \c clearChart() method simply changes the color to Qt::transparent,
repaints the chart, then emits the \c chartCleared() signal:
\snippet examples/tutorials/extending/chapter2-methods/piechart.cpp 0
Now when we run the application and click the window, the pie chart
disappears, and the application outputs:
\code
The chart has been cleared
\endcode
Try out the example yourself with the updated code in Qt's \c examples/tutorials/extending/chapter2-methods directory.
*/
/*!
\title Chapter 3: Adding Property Bindings
\example examples/tutorials/extending/chapter3-bindings
Property binding is a powerful feature of QML that allows values of different
elements to be synchronized automatically. It uses signals to notify and update
other elements' values when property values are changed.
Let's enable property bindings for the \c color property. That means
if we have code like this:
\snippet examples/tutorials/extending/chapter3-bindings/app.qml 0
\image extending-tutorial-chapter3.png
The "color: chartA.color" statement binds the \c color value of
\c chartB to the \c color of \c chartA.
Whenever \c chartA's \c color value changes, \c chartB's \c color value
updates to the same value. When the window is clicked, the \c onClicked
handler in the MouseArea changes the color of \c chartA, thereby changing
both charts to the color blue.
It's easy to enable property binding for the \c color property.
We add a \l{Qt's Property System}{NOTIFY} feature to its Q_PROPERTY() declaration to indicate that a "colorChanged" signal
is emitted whenever the value changes.
\snippet examples/tutorials/extending/chapter3-bindings/piechart.h 0
\dots
\snippet examples/tutorials/extending/chapter3-bindings/piechart.h 1
\dots
\snippet examples/tutorials/extending/chapter3-bindings/piechart.h 2
\dots
\snippet examples/tutorials/extending/chapter3-bindings/piechart.h 3
Then, we emit this signal in \c setPieSlice():
\snippet examples/tutorials/extending/chapter3-bindings/piechart.cpp 0
It's important for \c setColor() to check that the color value has actually changed
before emitting \c colorChanged(). This ensures the signal is not emitted unnecessarily and
also prevents loops when other elements respond to the value change.
The use of bindings is essential to QML. You should always add NOTIFY
signals for properties if they are able to be implemented, so that your
properties can be used in bindings. Properties that cannot be bound cannot be
automatically updated and cannot be used as flexibly in QML. Also, since
bindings are invoked so often and relied upon in QML usage, users of your
custom QML types may see unexpected behavior if bindings are not implemented.
*/
/*!
\title Chapter 4: Using Custom Property Types
\example examples/tutorials/extending/chapter4-customPropertyTypes
The \c PieChart type currently has a string-type property and a color-type property.
It could have many other types of properties. For example, it could have an
int-type property to store an identifier for each chart:
\code
// C++
class PieChart : public QQuickPaintedItem
{
Q_PROPERTY(int chartId READ chartId WRITE setChartId NOTIFY chartIdChanged)
...
public:
void setChartId(int chartId);
int chartId() const;
...
signals:
void chartIdChanged();
};
// QML
PieChart {
...
chartId: 100
}
\endcode
Aside from \c int, we could use various other property types. Many of the Qt
data types such as QColor, QSize and QRect are automatically supported from QML.
(See \l {Data Type Conversion Between QML and C++} documentation for a full list.)
If we want to create a property whose type is not supported by QML by default,
we need to register the type with the QML engine.
For example, let's replace the use of the \c property with a type called
"PieSlice" that has a \c color property. Instead of assigning a color,
we assign an \c PieSlice value which itself contains a \c color:
\snippet examples/tutorials/extending/chapter4-customPropertyTypes/app.qml 0
Like \c PieChart, this new \c PieSlice type inherits from QQuickPaintedItem and declares
its properties with Q_PROPERTY():
\snippet examples/tutorials/extending/chapter4-customPropertyTypes/pieslice.h 0
To use it in \c PieChart, we modify the \c color property declaration
and associated method signatures:
\snippet examples/tutorials/extending/chapter4-customPropertyTypes/piechart.h 0
\dots
\snippet examples/tutorials/extending/chapter4-customPropertyTypes/piechart.h 1
\dots
\snippet examples/tutorials/extending/chapter4-customPropertyTypes/piechart.h 2
\dots
\snippet examples/tutorials/extending/chapter4-customPropertyTypes/piechart.h 3
There is one thing to be aware of when implementing \c setPieSlice(). The \c PieSlice
is a visual item, so it must be set as a child of the \c PieChart using
QQuickItem::setParentItem() so that the \c PieChart knows to paint this child
item when its contents are drawn:
\snippet examples/tutorials/extending/chapter4-customPropertyTypes/piechart.cpp 0
Like the \c PieChart type, the \c PieSlice type has to be registered
using qmlRegisterType() to be used from QML. As with \c PieChart, we'll add the
type to the "Charts" module, version 1.0:
\snippet examples/tutorials/extending/chapter4-customPropertyTypes/main.cpp 0
\dots
\snippet examples/tutorials/extending/chapter4-customPropertyTypes/main.cpp 1
\dots
\snippet examples/tutorials/extending/chapter4-customPropertyTypes/main.cpp 2
Try it out with the code in Qt's \c examples/tutorials/extending/chapter4-customPropertyTypes directory.
*/
/*!
\title Chapter 5: Using List Property Types
\example examples/tutorials/extending/chapter5-listproperties
Right now, a \c PieChart can only have one \c PieSlice. Ideally a chart would
have multiple slices, with different colors and sizes. To do this, we could
have a \c slices property that accepts a list of \c PieSlice items:
\snippet examples/tutorials/extending/chapter5-listproperties/app.qml 0
\image extending-tutorial-chapter5.png
To do this, we replace the \c pieSlice property in \c PieChart with a \c slices property,
declared as a QQmlListProperty type. The QQmlListProperty class enables the
creation of list properties in QML extensions. We replace the \c pieSlice()
function with a \c slices() function that returns a list of slices, and add
an internal \c append_slice() function (discussed below). We also use a QList to
store the internal list of slices as \c m_slices:
\snippet examples/tutorials/extending/chapter5-listproperties/piechart.h 0
\dots
\snippet examples/tutorials/extending/chapter5-listproperties/piechart.h 1
\dots
\snippet examples/tutorials/extending/chapter5-listproperties/piechart.h 2
Although the \c slices property does not have an associated \c WRITE function,
it is still modifiable because of the way QQmlListProperty works.
In the \c PieChart implementation, we implement \c PieChart::slices() to
return a QQmlListProperty value and indicate that the internal
\c PieChart::append_slice() function is to be called whenever a request is made from QML
to add items to the list:
\snippet examples/tutorials/extending/chapter5-listproperties/piechart.cpp 0
The \c append_slice() function simply sets the parent item as before,
and adds the new item to the \c m_slices list. As you can see, the append function for a
QQmlListProperty is called with two arguments: the list property, and
the item that is to be appended.
The \c PieSlice class has also been modified to include \c fromAngle and \c angleSpan
properties and to draw the slice according to these values. This is a straightforward
modification if you have read the previous pages in this tutorial, so the code is not shown here.
The complete code can be seen in the updated \c examples/tutorials/extending/chapter5-listproperties directory.
*/
/*!
\title Chapter 6: Writing an Extension Plugin
\example examples/tutorials/extending/chapter6-plugins
Currently the \c PieChart and \c PieSlice types are used by \c app.qml,
which is displayed using a QQuickView in a C++ application. An alternative
way to use our QML extension is to create a plugin library to make it available
to the QML engine. This would allow the \c PieChart and \c PieSlice types to be
imported as part of a module by any QML application, instead of restricting these
types to be only used by the one application.
The setps for creating a plugin are described in \l {Creating C++ Plugins for QML}.
To start with, we create a plugin class named \c ChartsPlugin. It subclasses QQmlExtensionPlugin
and registers our QML types in the inherited \l{QQmlExtensionPlugin::}{registerTypes()} method.
Here is the \c ChartsPlugin definition in \c chartsplugin.h:
\snippet examples/tutorials/extending/chapter6-plugins/chartsplugin.h 0
And its implementation in \c chartsplugin.cpp:
\snippet examples/tutorials/extending/chapter6-plugins/chartsplugin.cpp 0
Then, we write a \c .pro project file that defines the project as a plugin library
and specifies with DESTDIR that library files should be built into a "lib" subdirectory:
\quotefile examples/tutorials/extending/chapter6-plugins/chapter6-plugins.pro
Finally, we add a \l{Adding Module Metadata with a qmldir file}{qmldir} file that is
automatically parsed by the QML engine. In this file, we specify that a plugin named
"chapter6-plugin" (the name of the example project) can be found in the "lib" subdirectory:
\quotefile examples/tutorials/extending/chapter6-plugins/ChartsPlugin/qmldir
Now we have a plugin, and instead of having a main.cpp and an executable, we can build
the project and then load the QML file using the \l{Prototyping with qmlscene}{qmlscene tool}:
\code
qmlscene app.qml
\endcode
Notice the "import Charts 1.0" statement has disappeared from \c app.qml. This is
because the \c qmldir file is in the same directory as \c app.qml: this is equivalent to
having PieChart.qml and PieSlice.qml files inside the project directory, which could both
be used by \c app.qml without import statements.
*/
/*!
\page qml-extending-tutorial7.html
\title Chapter 7: In Summary
In this tutorial, we've shown the basic steps for creating a QML extension:
\list
\li Define new QML types by subclassing QObject and registering them with qmlRegisterType()
\li Add callable methods using Q_INVOKABLE or Qt slots, and connect to Qt signals with an \c onSignal syntax
\li Add property bindings by defining \l{Qt's Property System}{NOTIFY} signals
\li Define custom property types if the built-in types are not sufficient
\li Define list property types using QQmlListProperty
\li Create a plugin library by defining a Qt plugin and writing a \c qmldir file
\endlist
The \l{Integrating QML and C++} documentation shows
other useful features that can be added to QML extensions. For example, we
could use \l{Default Property}{default properties} to allow
slices to be added without using the \c slices property:
\code
PieChart {
PieSlice { ... }
PieSlice { ... }
PieSlice { ... }
}
\endcode
Or randomly add and remove slices from time to time using \l{Property Value Sources}{property value sources}:
\code
PieChart {
PieSliceRandomizer on slices {}
}
\endcode
See the \l{Integrating QML and C++} documentation for more information.
*/

View File

@ -45,12 +45,16 @@
To write a QML extension plugin:
\list 1
\li Subclass QQmlExtensionPlugin
\li Implement QQmlExtensionPlugin's
\l{QQmlExtensionPlugin::}{registerTypes()} method
\li Register types with qmlRegisterType()
\li Export the class using the Q_EXPORT_PLUGIN2() macro
\list
\li Use the Q_PLUGIN_METADATA() macro to register the plugin with
the Qt meta object system
\li Override the \l{QQmlExtensionPlugin::}{registerTypes()} method
and call qmlRegisterType() to register the types to be exported
by the plugin
\endlist
\li Write a project file for the plugin
\li Create a \l{Adding Module Metadata with a qmldir file}{qmldir file} to describe the plugin
\li Create a \l{Adding Module Metadata with a qmldir file}{qmldir file} to
describe the plugin
\endlist
QML extension plugins are for either application-specific or library-like
@ -67,18 +71,14 @@
\snippet examples/qml/cppextensions/plugins/plugin.cpp 0
\dots
A plugin class, \c QExampleQMLPlugin, is a subclass of
\l QQmlExtensionPlugin and it implements the
\l{QQmlExtensionPlugin::}{registerTypes()} method.
In the registerTypes() method, the plugin class can
register the \c TimeModel class to the declarative
runtime with the qmlRegisterType() function. The Q_EXPORT_PLUGIN2() macro has
two parameters, the generated plugin name and the class name.
To make this type available, we create a plugin class named \c QExampleQmlPlugin
which is a subclass of \l QQmlExtensionPlugin. It overrides the
\l{QQmlExtensionPlugin::}{registerTypes()} method in order to register the \c TimeModel
type using qmlRegisterType(). It also uses the Q_PLUGIN_METADATA() macro in the class
definition to register the plugin with the Qt meta object system using a unique
identifier for the plugin.
\snippet examples/qml/cppextensions/plugins/plugin.cpp plugin
\codeline
\snippet examples/qml/cppextensions/plugins/plugin.cpp export
The \c TimeModel class receives a \c{1.0} version of this plugin library, as
a QML type called \c Time. The Q_ASSERT() macro can ensure the module is
@ -88,26 +88,27 @@
For this example, the TimeExample source directory is in
\c{com/nokia/TimeExample}. The plugin's module import statement will follow
this structure.
this structure, so the module is registered as "com.nokia.TimeExample".
The project file, in a \c .pro file, defines the project as a plugin library
and specifies it should be built into the \c com/nokia/TimeExample
directory:
Additionally, the project file, in a \c .pro file, defines the project as a plugin library,
specifies it should be built into the \c com/nokia/TimeExample directory, and registers
the plugin target name and various other details:
\code
TEMPLATE = lib
CONFIG += qt plugin
QT += declarative
QT += qml
DESTDIR = com/nokia/TimeExample
TARGET = qmlqtimeexampleplugin
...
SOURCES += qexampleqmlplugin.cpp
\endcode
Finally, a \l{Adding Module Metadata with a qmldir file}{qmldir file} is required in the \c
com/nokia/TimeExample directory to specify the plugin. This directory
includes a \c Clock.qml file that should be bundled with the plugin, so it
needs to be specified in the \c qmldir file:
Finally, a \l{Adding Module Metadata with a qmldir file}{qmldir file} is required
in the \c com/nokia/TimeExample directory to describe the plugin and the types that it
exports. The plugin includes a \c Clock.qml file along with the \c qmlqtimeexampleplugin
that is built by the project (as shown above in the \c .pro file) so both of these
need to be specified in the \c qmldir file:
\quotefile examples/qml/cppextensions/plugins/com/nokia/TimeExample/qmldir
@ -123,7 +124,7 @@
\section1 Reference
\list
\li \l {Tutorial: Extending QML with C++} - contains a chapter
\li \l {Writing QML Extensions with C++} - contains a chapter
on creating QML plugins.
\li \l{Defining QML Types from C++} - information about registering C++ types into
the runtime.

View File

@ -219,7 +219,7 @@ All QML plugins should extend QQmlExtensionPlugin in Qt 5.
Additionally, plugins should use the new Qt plugin infrastructure introduced in Qt 5. QML plugins no
longer require the Q_EXPORT_PLUGIN2() macro. Instead, they should use the Q_PLUGIN_METADATA() macro
within the plugin class declarations and provide a \c .json file for the plugin.
within the plugin class declaration.
See the updated \l {qtqml-modules-cppplugins.html}{Creating C++ Plugins For QML} documentation for
an overview of creating QML plugins in Qt 5.