创建QGis的自定义DataProvider

2022-06-21  本文已影响0人  NullUser

以TestProvider为例:

要实现DataProvider的基本功能,需要继承4个父类:

1. 新建QgsTestProviderMetadata类继承QgsProviderMetadata

class QgsTestProviderMetadata final: public QgsProviderMetadata
{
public:
    QgsSDEProviderMetadata();
    QgsDataProvider *createProvider( const QString &uri, const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags() ) override;
    QVariantMap decodeUri( const QString &uri ) const override;
    QString encodeUri( const QVariantMap &parts ) const override;
    void initProvider() override;
};

1.1 基础函数实现

1.1.1 重载函数

1) createProvider()

virtual QgsDataProvider *createProvider( const QString &uri,
        const QgsDataProvider::ProviderOptions &options,
        QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags() ) SIP_FACTORY;

createProvider()用以创建一个dataprovider实例,实现函数时new一个自定义的dataprovider对象,然后返回即可

QgsDataProvider *QgsTestProviderMetadata::createProvider(const QString &uri, const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags)
{
  return new QgsTestProvider( uri, options, flags );
}

2) decodeUri()

virtual QVariantMap decodeUri( const QString &uri ) const;

decodeUri()解析uri字符串,并以map结构返回解析后的数据,QGis提供了QgsDataSourceUri类,某些情况下可以直接使用QgsDataSourceUri类解析和生成uri字符串,省去了自己解析字符串的操作。参考postgresprovider的uri: dbname='sdetest' host=127.0.0.1 port=5432 user='sde' password='123' table="sde"."testlayer" (shape)。如果不用QgsDataSourceUri类,也可自定义字符串格式并自行解析。

QVariantMap QgsTestProviderMetadata::decodeUri(const QString &uri) const
{
    const QgsDataSourceUri dsUri{ uri };
    QVariantMap uriParts;

    if (!dsUri.database().isEmpty())
        uriParts[QStringLiteral("dbname")] = dsUri.database();
    if (!dsUri.host().isEmpty())
        uriParts[QStringLiteral("host")] = dsUri.host();
    return uriParts;
}

3) encodeUri()

virtual QString encodeUri( const QVariantMap &parts ) const;

同理,encodeUri的实现也可以借助QgsDataSourceUri类生成uri字符串。

QString QgsTestProviderMetadata::encodeUri(const QVariantMap &parts) const
{
    QgsDataSourceUri dsUri;
    if (parts.contains(QStringLiteral("dbname")))
        dsUri.setDatabase(parts.value(QStringLiteral("dbname")).toString());
    if (parts.contains(QStringLiteral("port")))
        dsUri.setParam(QStringLiteral("port"), parts.value(QStringLiteral("port")).toString());
    return dsUri.uri(false);
}

4) initProvider()

void initProvider() override;

2. 新建QgsTestProvider类继承QgsVectorDataProvider

class QgsTestProvider final: public QgsVectorDataProvider
{
    friend class QgsTestFeatureSource;
    Q_OBJECT
public:
    explicit QgsTestProvider( QString const &uri, const QgsDataProvider::ProviderOptions &providerOptions,
                                  QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags() );
    ~QgsTestProvider();

    virtual QgsAbstractFeatureSource *featureSource() const override;
    QgsFeatureIterator getFeatures( const QgsFeatureRequest &request = QgsFeatureRequest() ) const override;
    QgsWkbTypes::Type wkbType() const override;
    long long featureCount() const override;
    QgsFields fields() const override;
    QgsCoordinateReferenceSystem crs() const override;
    QgsRectangle extent() const override;
    bool isValid() const override;
    QString name() const override;
    QString description() const override;
private:
    /**
     * Flag indicating if the layer data source is a valid PostgreSQL layer
     */
    bool mValid = false;

    QgsWkbTypes::Type mWkbType;

    QgsFields mAttributeFieds;

    QgsRectangle mExtent;

    QList<QgsFeature> mFeatures;
};

QgsTestProvider重载QgsVectorDataProvider的纯虚函数:

重载QgsDataProvider的纯虚函数:

2.1 基础函数实现

2.1.1 实现QgsVectorDataProvider的纯虚函数

1) featureSource()

virtual QgsAbstractFeatureSource *featureSource() const = 0 SIP_FACTORY;

featureSource()返回自定义的QgsTestFeatureSource对象即可,QgsTestFeatureSource继承自QgsAbstractFeatureSource

QgsAbstractFeatureSource *QgsTestProvider::featureSource() const
{
  return new QgsTestFeatureSource( this );
}

2) getFeatures()

QgsFeatureIterator getFeatures( const QgsFeatureRequest &request = QgsFeatureRequest() ) const override = 0;

getFeatures()返回一个迭代器,通过该迭代器遍历features,同样也需要新建类QgsTestFeatureIterator继承自QgsAbstractFeatureIteratorFromSource<QgsTestFeatureSource>

QgsFeatureIterator QgsTestProvider::getFeatures( const QgsFeatureRequest &request ) const
{
  QgsTestFeatureSource *featureSrc = static_cast<QgsTestFeatureSource *>( featureSource() );
  return QgsFeatureIterator( new QgsTestFeatureIterator( featureSrc, true, request ) );
}

3) wkbType()

QgsWkbTypes::Type wkbType() const override = 0;

wkbType()返回feature的类型,该类型为qgswkbtypes.h中QgsWkbTypes::Type枚举。在自定义Provider中定义一个私有变量存放该类型,则返回该变量值即可。

QgsWkbTypes::Type QgsTestProvider::wkbType() const
{
    return mWkbType;
}

4) featureCount()

long long featureCount() const override = 0;

返回要素数量。

5) fields()

QgsFields fields() const override = 0;

fields()返回属性字段,QGis提供了一个QgsFields类去储存属性字段,可以在provider内定义一个该类对象为成员变量,fields()直接返回该对象即可

QgsFields mAttributeFields;
QgsFields QgsTestProvider::fields() const
{
  return mAttributeFields;
}

QgsFields提供append函数添加属性字段,每个字段的具体数据由QgsField对象持有。

        QgsField f1;
        f1.setName(QStringLiteral("name"));
        f1.setType(QVariant::Int);
        f1.setTypeName(QStringLiteral("typename"));
        f1.setLength(5);
        f1.setPrecision(1);
        f1.setComment(QStringLiteral("comment"));
        mAttributeFieds.append(f1);

2.1.2 还有一部分是QgsDataProvider的纯虚函数需要实现

1) crs()

virtual QgsCoordinateReferenceSystem crs() const = 0;

crs()返回坐标参考系

2) extent()

virtual QgsRectangle extent() const = 0;

extent()返回图层的范围,将读取到的数据以QgsRectangle对象返回,这里以一个成员变量mExtent储存数据。

QgsRectangle QgsTestProvider::extent() const
{
    //mExtent.setXMinimum(97.3475);
    //mExtent.setXMaximum(108.543);
    //mExtent.setYMinimum(26.0482);
    //mExtent.setYMaximum(34.3152);
    return mExtent;
}

3) isValid()

virtual bool isValid() const = 0;

isValid()返回该图层是否有效。返回自定义的成员变量即可

bool QgsTestProvider::isValid() const
{
  return mValid;
}

4) name()

virtual QString name() const = 0;

name()返回provider的key

QString  QgsTestProvider::name() const
{
    return TEXT_PROVIDER_KEY;
}

5) description()

virtual QString description() const = 0;

description()返回provider描述

QString  QgsTestProvider::description() const
{
    return TEXT_PROVIDER_DESCRIPTION;
}

2.1.3 重载函数

3. 新建QgsTestFeatureSource类继承QgsAbstractFeatureSource

class QgsTestFeatureSource final: public QgsAbstractFeatureSource
{};

3.1 基础函数实现

3.1.1 实现QgsAbstractFeatureSource的纯虚函数

1) getFeatures()

    virtual QgsFeatureIterator getFeatures( const QgsFeatureRequest &request = QgsFeatureRequest() ) = 0 SIP_TRANSFERBACK;

getFeatures()返回QgsFeatureIterator对象, 通过QgsFeatureIterator( QgsAbstractFeatureIterator *iter SIP_TRANSFER )构造函数创建一个有效的迭代器,构造函数实参传入自定义的FeatureIterator。

QgsFeatureIterator QgsTestFeatureSource::getFeatures( const QgsFeatureRequest &request )
{
  return QgsFeatureIterator( new QgsTestFeatureIterator( this, false, request ) );
}

4. 新建QgsTestFeatureIterator类继承QgsAbstractFeatureIteratorFromSource<QgsSDEFeatureSource>

4.1 基础函数实现

4.1.1 实现QgsAbstractFeatureIterator的纯虚函数

1) rewind()

    virtual bool rewind() = 0;

rewind()将迭代器重置到起始位置,在QgsTestFeatureIterator中定义成员变量mIterator用以遍历feature,mIterator类型可以根据储存feature的数据结构确定,以QList为例,则定义为:QList<QgsFeature>::iterator mIterator;
mClosed变量为父类QgsAbstractFeatureIterator的成员变量,当迭代器关闭时,该变量应置为true。

bool QgsTestFeatureIterator::rewind()
{
    if (mClosed)
    {
        return false;
    }

    mIterator = mSource->mFeatures.begin();

    return true;
}

2) close()

    virtual bool close() = 0;

close()用以关闭迭代器,函数体内直接调用父类QgsAbstractFeatureIteratorFromSource的iteratorClosed()即可

bool QgsTestFeatureIterator::close()
{
    if (mClosed)
    {
        return false;
    }
    iteratorClosed();
    return true;
}

查看QgsAbstractFeatureIteratorFromSource::iteratorClosed()源码可知,其也是直接调用QgsAbstractFeatureSource的iteratorClosed()函数

template<typename T>
class QgsAbstractFeatureIteratorFromSource : public QgsAbstractFeatureIterator
{
  ......
  protected:
    //! to be called by from subclass in close()
    void iteratorClosed() { mSource->iteratorClosed( this ); }
  ......
};

3) fetchFeature()

protected:
  virtual bool fetchFeature( QgsFeature &f ) = 0;

fetchFeature()获取下一个feature,内部实现也是通过mIterator迭代,将获得的feature赋值给形参feature。

bool QgsTestFeatureIterator::fetchFeature(QgsFeature &feature)
{
    if (mClosed)
    {
        return false;
    }

    if (mIterator != mSource->mFeatures.end())
    {
        feature = *mIterator;
        mIterator++;
        return true;
    }
    else
    {
        close();
        return false;
    }
}
上一篇下一篇

猜你喜欢

热点阅读