本页内容

地点后端

概述

QPlaceManager 接口向客户端提供访问地点信息的途径,该接口直接依赖于QPlaceManagerEngine 的实现。引擎提供后端函数的实现,这些函数由管理器调用。

地点后端实现者需要继承自QPlaceManagerEngine ,并为其后端相关的虚函数提供实现。这些函数大多是异步的,因此实现者还需要派生相应的回复类。 响应对象负责管理异步请求;它们用于在请求完成时发出通知,并保存该请求的结果。QPlaceManagerEngine 为所有虚函数提供了默认实现。异步函数的默认实现会返回一个响应对象,该对象将在事件循环的下一次迭代中发出 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 的实现必须确保回复对象发出的任何信号都会被延迟,直到请求函数返回且应用程序代码有机会将这些信号连接到槽(slot)为止。典型的做法是使用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 的信号应始终被发出,即使遇到了错误也是如此;也就是说,如果发生错误,应同时发出error 和finished 信号;而如果没有错误,则仅发出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() 函数。该函数返回输入地点的副本,并根据需要对属性进行精简或修改,以便该副本能够保存到管理器中。

构建兼容的“地点”可能需要忽略原始“地点”中的某些属性,例如,如果系统不支持联系信息,则这些信息将不会被包含在兼容的“地点”中。在其他情况下,可能需要修改某些属性,例如修改图标参数,以便将原始“地点”的图标复制或下载到后端可访问的位置。

管理器之间的地点交叉引用

有时可能会出现需要在不同管理器之间进行位置交叉引用和匹配的情况。例如,当一个管理器(源管理器)仅提供位置的只读访问权限,而另一个读写管理器(目标管理器)用于将选定的收藏项从源管理器保存至目标管理器时,就会出现这种情况。 在对源管理器进行搜索时,我们可能希望了解哪些位置已被“添加到收藏”并保存到了目标管理器中,并且可能希望显示自定义的收藏名称,而不是原始名称。

替代标识符交叉引用

为了实现交叉引用,原始地点与被收藏的地点之间需要建立关联,这通常通过“替代标识符”属性来实现。被收藏的地点包含一个“替代标识符”属性,该属性存储了原始地点的标识符。

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

通过替代标识符实现交叉引用有 3 个先决条件。首先,源管理器必须提供 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 请求,其中参数 key 为 'proximity',参数 value 则为检测匹配时两个地点之间必须满足的距离阈值。例如,如果源地点和目标地点相距在50米以内,则可视为同一地点。

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

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

如果某个属性不打算供最终用户阅读,则应将标签字段留空,以此作为该属性的标识。

© 2026 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.