Chapter 5: Using List Property Types(章节五:使用列表类型)
extending-qml/chapter5-listproperties
目前,一个PieChart只能有一个PieSlice。理想情况下,图表应该有多个不同颜色和大小的切片。为此,我们可以有一个接受PieSlice项列表的Slices属性:
import Charts 1.0
import QtQuick 2.0
Item {
width: 300; height: 200
PieChart {
anchors.centerIn: parent
width: 100; height: 100
slices: [
PieSlice {
anchors.fill: parent
color: "red"
fromAngle: 0; angleSpan: 110
},
PieSlice {
anchors.fill: parent
color: "black"
fromAngle: 110; angleSpan: 50
},
PieSlice {
anchors.fill: parent
color: "blue"
fromAngle: 160; angleSpan: 100
}
]
}
}
为此,我们用声明为QQmlListProperty类型的Slices属性替换PieChart中的PieSlice属性。QQmlListProperty类允许在QML扩展中创建列表属性。我们用一个返回切片列表的Slices()函数替换PieSlice()函数,并添加一个内部append_Slice()函数(如下所述)。我们还使用QList将内部切片列表存储为m_Slices:
class PieChart : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(QQmlListProperty<PieSlice> slices READ slices)
...
public:
...
QQmlListProperty<PieSlice> slices();
private:
static void append_slice(QQmlListProperty<PieSlice> *list, PieSlice *slice);
QString m_name;
QList<PieSlice *> m_slices;
};
尽管Slices属性没有关联的写入函数,但由于QQmlListProperty的工作方式,它仍然是可修改的。
在Piechart实现中,我们实现Piechart::Slices()以返回QQmlListProperty值,并指示无论何时从QML请求向列表添加项目时都要调用内部Piechart::append_Slice()函数:
QQmlListProperty<PieSlice> PieChart::slices()
{
return QQmlListProperty<PieSlice>(this, nullptr, &PieChart::append_slice, nullptr, nullptr, nullptr);
}
void PieChart::append_slice(QQmlListProperty<PieSlice> *list, PieSlice *slice)
{
PieChart *chart = qobject_cast<PieChart *>(list->object);
if (chart) {
slice->setParentItem(chart);
chart->m_slices.append(slice);
}
}
Append_Slice()函数只需像以前一样设置父项,并将新项添加到m_slices列表。
如您所见,QQmlListProperty的Append函数是用两个参数调用的:List属性和要追加的项。
PieSlice类也进行了修改,以包括FromAngel和angleSpan属性,并根据这些值绘制切片。
Chapter 6: Writing an Extension Plugin(章节六:编写一个扩展插件)
extending-qml/chapter6-plugins
目前app.qml使用PieChart和PieSlice类型,它在C++应用程序中使用QQuickView显示。
使用我们的QML扩展的另一种方法是创建一个插件库,使其作为新的QML导入模块可供QML引擎使用。
这允许Piehart和PieSlice类型注册到可由任何QML应用程序导入的类型命名空间中,而不是将这些类型限制为仅由一个应用程序使用。
创建QML的C++插件中介绍了创建插件的步骤。
首先,我们创建一个名为ChartsPlugin的插件类。
它将QQmlExtensionPlugin子类化,并在继承的registerTypes()方法中注册我们的QML类型。
以下是chartplugin.h中的ChartsPlugin定义:
#include <QQmlExtensionPlugin>
class ChartsPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
void registerTypes(const char *uri);
};
及其在chartplugin.cpp中的实现:
#include "piechart.h"
#include "pieslice.h"
#include <qqml.h>
void ChartsPlugin::registerTypes(const char *uri)
{
qmlRegisterType<PieChart>(uri, 1, 0, "PieChart");
qmlRegisterType<PieSlice>(uri, 1, 0, "PieSlice");
}
然后,我们编写一个.pro项目文件,该文件将项目定义为插件库,并使用DESTDIR指定库文件应构建到…/Charts目录中。
TEMPLATE = lib
CONFIG += plugin
QT += qml quick
DESTDIR = ../Charts
TARGET = $$qtLibraryTarget(chartsplugin)
HEADERS += piechart.h \
pieslice.h \
chartsplugin.h
SOURCES += piechart.cpp \
pieslice.cpp \
chartsplugin.cpp
DESTPATH=$$[QT_INSTALL_EXAMPLES]/qml/tutorials/extending-qml/chapter6-plugins/Charts
target.path=$$DESTPATH
qmldir.files=$$PWD/qmldir
qmldir.path=$$DESTPATH
INSTALLS += target qmldir
CONFIG += install_ok # Do not cargo-cult this!
OTHER_FILES += qmldir
# Copy the qmldir file to the same folder as the plugin binary
cpqmldir.files = qmldir
cpqmldir.path = $$DESTDIR
COPIES += cpqmldir
在Windows或Linux上构建此示例时,Charts目录将与使用新导入模块的应用程序位于同一级别。
这样,QML引擎将找到我们的模块,因为QML导入的默认搜索路径包括应用程序可执行文件的目录。
在MacOS上,插件二进制文件被复制到应用程序包中的Contents/Plugin中;此路径 chapter6-plugins/app.pro:
osx {
charts.files = $$OUT_PWD/Charts
charts.path = Contents/PlugIns
QMAKE_BUNDLE_DATA += charts
}
为此,我们还需要在main.cpp中添加此位置作为QML导入路径:
QQuickView view;
#ifdef Q_OS_OSX
view.engine()->addImportPath(app.applicationDirPath() + "/../PlugIns");
#endif
...
当有多个应用程序使用相同的QML导入时,定义自定义导入路径也很有用。
Pro文件还包含额外的魔力,以确保始终将模块定义qmldir文件复制到与插件二进制文件相同的位置。
Qmldir文件声明模块名称和模块提供的插件:
module Charts
plugin chartsplugin
现在我们有了一个可以导入到任何应用程序的QML模块,只要QML引擎知道在哪里可以找到它。
该示例包含一个加载app.qml的可执行文件,该文件使用IMPORT Charts 1.0版本。
或者,也可以使用qmlScene工具加载QML文件,将导入路径设置为当前目录,以便找到qmldir文件:
qmlscene -I . app.qml
模块“Charts”将由QML引擎加载,该模块提供的类型将可用于任何导入它的QML文档。
教程完。