地点后台

概述

QPlaceManager 接口提供给客户端以允许访问地点信息,它直接依赖于QPlaceManagerEngine 的实现。该引擎提供由管理器调用的后端函数实现。

位置后端实现者需要从QPlaceManagerEngine 派生,并为其后端相关的虚拟函数提供实现。这些函数大多是异步函数,因此实现者还需要派生相应的回复类。reply 对象负责管理异步请求;它们用于在请求完成时发出通知并保存请求结果。QPlaceManagerEngine 为所有虚拟函数提供了默认实现。异步函数的默认实现将返回一个 reply,该 reply 将在事件循环的下一次迭代中发出 errorOccurred() 和 finished() 信号。

实现/继承回复对象

回复对象的继承方式如下:

class SearchReply : public QPlaceSearchReply
{
public:
    explicit SearchReply(ManagerEngine *engine)
        : QPlaceSearchReply(engine), m_engine(engine){}

    ~SearchReply();
    void setResults(const QList<QPlaceSearchResult> &results);
    void setRequest(const QPlaceSearchRequest &request);
    ...
    void triggerDone(QPlaceReply::Error error = QPlaceReply::NoError,
                     const QString &errorString = QString());

    ManagerEngine *m_engine;
};

QPlaceManagerEngine 的实现必须确保回复对象发出的任何信号都延迟到请求函数返回后,应用程序代码才有机会将这些信号连接到插槽。典型的方法是使用QMetaObject::invokeMethod() 和Qt::QueuedConnection 来发射信号。

void SearchSuggestionReply::triggerDone(QPlaceReply::Error error,
                         const QString &errorString)
{
    if (error != QPlaceReply::NoError) {
        this->setError(error,errorString);
        QMetaObject::invokeMethod(m_engine, "errorOccurred", Qt::QueuedConnection,
                                  Q_ARG(QPlaceReply *,this),
                                  Q_ARG(QPlaceReply::Error, error),
                                  Q_ARG(QString, errorString));
        QMetaObject::invokeMethod(this, "errorOccurred", Qt::QueuedConnection,
                                  Q_ARG(QPlaceReply::Error, error),
                                  Q_ARG(QString, errorString));
    }

    this->setFinished(true);
    QMetaObject::invokeMethod(m_engine, "finished", Qt::QueuedConnection,
                              Q_ARG(QPlaceReply *,this));
    QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
}

请注意,finished 信号应始终在应答完成时发出,即使遇到错误也是如此,也就是说,如果出现错误,errorfinished 信号都应发出,而如果没有错误,则只发出finished 信号。

QPlaceSearchReply::setResults() 和QPlaceSearchReply::setRequest() 的受保护函数是公开访问的,因此插件可以分配结果和请求。由于这些函数不是公开导出的,因此可访问性并不是一个大问题。另一种方法是在 SearchReply 中声明一个友类。

通常情况下,引擎实例将成为回复的parent 。如果开发人员没有在完成后丢弃回复,引擎可以在销毁时清理这些回复。通常,回复也有一个指向引擎的指针引用,可用于发出QPlaceManagerEngine::finished() 和 QPlaceManagerEngine::error() 信号。这只是实现回复的多种方法之一。

图标 URL

图标 URL 通过QPlaceManagerEngine::constructIconUrl() 函数提供。预期的行为是,引擎将使用QPlaceIcon::parameters() 来构建适当的 URL。当管理器通过搜索或查询返回QPlace 对象以获取地点详细信息时,预计引擎将根据需要正确填充参数。

后端可自由选择参数键和值,但如果后端每个图标只有一个 URL,建议使用QPlaceIcon::SingleUrl 作为键。

类别

管理器引擎的类别是相对静态的实体;对于访问远程位置数据存储的引擎来说,缓存类别结构可能比每次调用QPlaceManagerEngine::initializeCategories() 时查询服务器更可取。根据类别的动态程度,始终下载最新的类别集可能更合适。

将地点保存到管理器

由于位置包含图标和类别等管理器特定数据,因此通常无法在管理器之间直接保存。为了便于保存到自己的管理器,引擎实现者应该实现QPlaceManagerEngine::compatiblePlace() 函数。该函数会返回一个输入位置的副本,并根据需要对属性进行修剪或修改,以便将副本保存到管理器中。

构建兼容位置可能会忽略原始位置的某些属性,例如,如果不支持联系方式,兼容位置中就不会包含这些属性。有时可能需要修改某些属性,例如修改图标参数,以方便复制或下载原始位置的图标到后台可以访问的位置。

在管理器之间交叉引用位置

有时,我们可能希望在管理器之间交叉引用和匹配地点。在这种情况下,一个管理器提供对位置的只读访问(原点管理器),而另一个 r/w 管理器(目的地管理器)用于保存从第一个管理器中选择的收藏夹。在搜索原点管理器时,我们可能想知道哪些地方已被 "收藏 "到目的地管理器中,并显示定制的收藏夹名称,而不是原始名称。

替代标识符交叉引用

为了实现交叉引用,需要在原始地点和收藏地点之间建立联系,这通常是通过替代标识符属性来实现的。被收藏地点包含一个替代标识符属性,该属性具有原始地点的标识符。

origin R/O manager(here)       destination R/W manager (places_jsondb)
                        Save
Place id: ae246         --->    Place id: 0001
Attribute type: x_provider      Attribute type: x_id_here
Attribute value: here           Attribute text value: ae246

通过替代标识符实施交叉引用有三个先决条件。首先,起源管理器必须提供 x_provider 属性,其值为管理器的名称QGeoServiceProvider 。属性标签应为空,表示该属性不应显示给用户。

注意: 一般来说,所有管理器都应设置x_provider 属性。

第二种情况是,目的地管理器的QPlaceManager::compatiblePlace() 使用初始位置的x_provider 属性,并设置要保存位置的替代标识符属性。替代标识符属性的键是x_id_<provider name>,文本值是初始位置的标识符。x_provider 属性不应传递给兼容地点。保存时,保存位置的 x_provider 将被视为目标管理器。

第三种情况是,目的地管理器的QPlaceManager::matchingPlaces() 接受QPlaceMatchRequest::AlternativeId 作为参数键,并接受替代标识符属性键作为值,在这种情况下,x_id_<provider name> 将是预期值。这表明QPlaceMatchRequest 中的地点标识符应与x_id_<provider name> 备选标识符属性相匹配。

请注意,如果目标管理器要便于保存和交叉引用任意管理器的内容,那么它内部就必须能够保存任意键值对,因为我们无法事先知道提供者的名称,也无法知道 id 将是什么结构。

其他链接方法

如果起源管理器不提供地点 ID,则可能需要提供其他交叉引用/匹配方法。一种方法可能是通过地点坐标来实现,如果原点管理器中的地点坐标与目的地管理器中的地点坐标相同或接近,那么它们很有可能是同一个地点。在这种情况下,管理器可以执行QPlaceManager::matchingPlaces() 来接受一个QPlaceMatchRequest ,该 的参数键为 "接近度",参数值为两个地点之间的距离,以便检测是否匹配。例如,如果起始地点和目的地的距离在 50 米以内,就可以认为它们是同一个地点。

不过,一般来说,建议通过上述替代标识符来实现交叉引用。

用户可读与非用户可读扩展属性

如果一个属性不打算让最终用户读取,标签字段应保持为空,以表明这一事实。

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.