地点 (C++)

概览

地点 API 允许用户发现地点/兴趣点,并查看它们的相关详细信息,如地址和联系信息;有些地点甚至还会有丰富的内容,如图片和评论。地点 API 还便于管理和分类地点,使用户可以保存和删除它们。

地点定义

地点是一个兴趣点,它可以是一家喜欢的餐厅、一个公园或者某人的家。《QPlace》对象通过作为包含该地点各种信息的容器来表示地点。

这些信息可以分为两大类

  • 详细信息
  • 丰富内容

地点详细信息包括地点的属性,如名称、位置、联系信息等。在搜索过程中返回地点时,这些详细信息将被填写。有时为了节省带宽,还可以按地点单独获取有关地点的更多详细信息,如果用户感兴趣的话。可以通过查询QPlace::detailsFetched() 函数来查看是否已获取所有可用详细信息,如果没有,则可以使用 QPlaceManager::getPlaceDetails() 来获取它们。在搜索过程中精确填充哪些详细信息,以及哪些需要单独获取,这可能会因提供商而异。有关更多详细信息,请参阅 插件文档

地点的丰富内容包含图片、评论和编辑等项。可能有很多丰富内容项,因此它们与地点详细信息分开处理。可以通过 QPlaceManager::getPlaceContent() 以分页的方式检索。如果需要,可以将内容分配给地点,以便它作为一个方便的容器。

常用操作

初始化管理器

所有地点功能都是由一个 QPlaceManager 实例提供的。必须指定一个 QGeoServiceProvider 才能创建 QPlaceManager

//The "provider name" is used to select a particular provider
QGeoServiceProvider *provider = new QGeoServiceProvider("provider name");
QPlaceManager *manager = provider->placeManager();

为了执行搜索操作,我们只需创建一个 QPlaceSearchRequest 并设置所需的搜索参数,例如搜索词和搜索中心。

//instantiate request and set parameters
QPlaceSearchRequest searchRequest;
searchRequest.setSearchTerm("ice cream");
searchRequest.setSearchArea(QGeoCircle(QGeoCoordinate(12.34, 56.78)));

//send off a search request
/*QPlaceSearchReply * */ searchReply = manager->search(searchRequest);

//connect a slot to handle the reply
connect(searchReply, &QPlaceSearchReply::finished, this, &RequestHandler::handleSearchReply);

请求是一个异步操作,因此我们需要一个槽来处理请求的完成。在处理程序中,我们检查是否存在错误以及我们的搜索结果类型是否为地点。如果是的话,我们就可以检索地点的一些核心详细信息。在槽的末尾,我们删除回复,因为它们仅用于单次使用。

void handleSearchReply() {
    if (searchReply->error() == QPlaceReply::NoError) {
        for (const QPlaceSearchResult &result : searchReply->results()) {
            if (result.type() == QPlaceSearchResult::PlaceResult) {
                QPlaceResult placeResult = result;
                qDebug() << "Name: " << placeResult.place().name();
                qDebug() << "Coordinate " << placeResult.place().location().coordinate().toString();
                qDebug() << "Street: " << placeResult.place().location().address().street();
                qDebug() << "Distance: " << placeResult.distance();
            }
        }
    }
    searchReply->deleteLater();  //discard reply
    searchReply = nullptr;
}

注意: 根据所选择的插件后端,搜索结果可能包含有更多详细信息的地点,这些详细信息可以逐个地点检索。要获取这些其他详细信息,请参阅检索地点详细信息

推荐

可以通过在QPlaceSearchRequest::setRecommendationId()中提供地点ID来检索推荐。检索与给定地点相似的地点。

分页

如果插件支持分页,则可以将限制参数提供到搜索请求中。

QPlaceSearchRequest searchRequest;
searchRequest.setLimit(15); //specify how many results are to be retrieved.

检索地点详细信息

从搜索请求返回的地点可能有更多详细信息可以检索。以下演示了如何检查是否存在详细信息以及如何请求它们。

if (!place.detailsFetched()) {
    /*QPlaceDetailsReply * */ detailsReply = manager->getPlaceDetails(place.placeId());
    connect(detailsReply, &QPlaceDetailsReply::finished, this, &RequestHandler::handleDetailsReply);
}
    ...
    ...
void handleDetailsReply() {
    QPlace place;
    if (detailsReply->error() == QPlaceReply::NoError)
        place = detailsReply->place();

    detailsReply->deleteLater(); //discard reply
    detailsReply = nullptr;
}

检索丰富内容

图像和评论等丰富内容是通过管理器检索的,然后(如果需要)分配给地点。

QPlaceContentRequest request;
request.setContentType(QPlaceContent::ImageType);
request.setPlaceId(place.placeId());
request.setLimit(5);
/*QPlaceContentReply * */ contentReply = manager->getPlaceContent(request);
connect(contentReply, &QPlaceContentReply::finished, this, &RequestHandler::handleImagesReply);

我们可以按以下方式处理内容请求。

void handleImagesReply() {
    if (contentReply->error() == QPlaceReply::NoError) {
        const auto content = contentReply->content();
        for (auto iter = content.cbegin(), end = content.cend(); iter != end; ++iter) {
            qDebug() << "Index: " << iter.key();
            QPlaceImage image = iter.value();
            qDebug() << image.url();
            qDebug() << image.mimeType();
        }

        //alternatively if indexes are irrelevant
        for (const QPlaceImage &image : contentReply->content()) {
            qDebug() << image.url();
            qDebug() << image.mimeType();
        }

        //we can assign content to the place that it belongs to.
        //the place object serves as a container where we can retrieve
        //content that has already been fetched
        place.insertContent(contentReply->request().contentType(), contentReply->content());
        place.setTotalContentCount(contentReply->request().contentType(), contentReply->totalCount());
    }

    contentReply->deleteLater();
    contentReply = nullptr;
}

需要注意的是,在QPlaceContentReply中的结果是QPlaceContent::Collection,它实际上是QMap<int, QPlaceContent>。其中键int在这种情况下是内容的索引,值是内容本身。由于内容实现的特定方式,可以按以下方式将内容类型转换为

QPlaceImage image = content; //provided that 'content' has a type QPlace::ImageType

QPlaceContent::Collection的使用以及内容及其子类型之间的转换意味着处理分页评论、图像和评论的机制代码可以轻松共享。

搜索建议

检索搜索词建议的方式与执行地点搜索非常相似。使用QPlaceSearchRequest的方式与地点搜索相同,唯一的区别是将搜索词设置为不完全字符串。

QPlaceSearchRequest request;
request.setSearchTerm("piz");
request.setSearchArea(QGeoCircle(QGeoCoordinate(12.34, 56.78)));
/* QPlaceSearchSuggestion * */suggestionReply = manager->searchSuggestions(request);
connect(suggestionReply, &QPlaceSearchSuggestion::finished, this, &RequestHandler::handleSuggestionReply);

当请求完成后,我们可以使用回复来显示建议。

void handleSuggestionReply() {
    if (suggestionReply->error() == QPlaceReply::NoError) {
        for (const QString &suggestion : suggestionReply->suggestions())
            qDebug() << suggestion;
    }

    suggestionReply->deleteLater(); //discard reply
    suggestionReply = nullptr;
}

保存地点

新地点的保存操作如下:我们创建一个QPlace实例,并用诸如名称、地址和坐标等信息填充它。完成后,我们可以调用QPlaceManager::savePlace()来开始保存操作。

QPlace  place;
place.setName( "Fred's Ice Cream Parlor" );

QGeoLocation location;
location.setCoordinate(QGeoCoordinate(12.34, 56.78));

QGeoAddress address;
address.setStreet("111 Nother Street");
    ...
location.setAddress(address);
place.setLocation(location);

/* QPlaceIdReply * */savePlaceReply = manager->savePlace(place);
connect(savePlaceReply, &QPlaceIdReply::finished, this, &RequestHandler::handleSavePlaceReply);

一旦地点被保存,回复将包含该地点的新标识符。

void handleSavePlaceReply() {
    if (savePlaceReply->error() == QPlaceReply::NoError)
        qDebug() << savePlaceReply->id();

    savePlaceReply->deleteLater(); //discard reply
    savePlaceReply = nullptr;
}

请注意,要保存已存在的地点,必须在QPlace::placeId()中填写正确的标识符。否则,如果标识符为空或错误,将创建一个新地点,或覆盖错误标识符的地点。

地点保存时,QPlaceManager可能会发出QPlaceManager::placedAddedQPlaceManager::placeUpdated信号。然而,是否发出这些信号由提供者特定,从网络服务访问地点的管理器通常不会发出这些信号,而从本地存储访问地点的管理器通常会发出这些信号。

注意事项

当前,地点API设计为仅保存核心详情。保存图像和评论等丰富内容或供应商和评分等详细信息的用例不受支持。通常,管理器会在保存时忽略这些字段,并在它们被填充时产生一个警告消息。

地名API只支持保存以下核心细节

  • 名称
  • 地点ID
  • 位置
  • 联系详情
  • 图标
  • 类别(类似标签的名称,用于描述地点)
  • 可见性范围

提供者可能只支持这些细节的子集。有关更多信息,请参阅插件文档

评分、扩展属性、图片、评论、编辑和供应商等属性的保护直接不受地名API的支持。

在管理者之间保存

在管理者之间保存地点时,有一些事项需要注意。地点的一些字段(如ID、类别和图标)是特定于管理者的实体,例如,在一个管理者中的类别可能不会被另一个管理者识别。因此,直接从一个管理者保存地点到另一个管理者是不可能的。

典型的方法是使用QPlaceManager::compatiblePlace()函数,它创建地点的副本,但仅复制管理者支持的数据。特定于管理者的数据,如地点标识符,不会被复制。现在这个新副本可以保存到管理者中。如果管理者支持通过替代标识符进行匹配,则将替代标识符属性分配给副本(参见在管理者之间匹配地点

//result retrieved from a different manager)
QPlace place = manager->compatiblePlace(result.place());
saveReply = manager->savePlace(place);

删除地点

删除地点的操作如下

/* QPlaceIdReply * */removePlaceReply = manager->removePlace(place.placeId());
connect(removePlaceReply, &QPlaceIdReply::finished, this, &RequestHandler::handleRemovePlaceReply);
    ...
    ...
void handleRemovePlaceReply() {
    if (removePlaceReply->error() == QPlaceReply::NoError)
        qDebug() << "Removal of place identified by"
                 << removePlaceReply->id() << "was successful";

    removePlaceReply->deleteLater(); //discard reply
    removePlaceReply = nullptr;
}

当删除地点时,QPlaceManager可能会发出QPlaceManager::placeRemoved()信号。是否发出此信号取决于提供者。从网络服务访问地点的管理者通常会发出这些信号,而访问本地存储的地点的管理者通常会发出。

使用类别

类别是描述地点的关键词。例如,'公园'、'剧院'、'餐厅'。地点可以由很多类别描述,它可能是一个公园和音乐场馆,也可能是轮渡站或公交站。

要使用类别,必须首先初始化它们。

/* QPlaceReply * */initCatReply = manager->initializeCategories();
connect(initCatReply, &QPlaceReply::finished, this, &RequestHandler::handleInitCatReply);
    ...
    ...
void handleInitCatReply() {
    if (initCatReply->error() == QPlaceReply::NoError)
        qDebug() << "Categories initialized";
    else
        qDebug() << "Failed to initialize categories";

    initCatReply->deleteLater();
    initCatReply = nullptr;
}

类别初始化之后,我们就可以使用以下这些类别函数。

要检索顶级类别,我们使用QPlaceManager::childCategories()函数,但不提供类别ID。

const QList<QPlaceCategory> topLevelCategories = manager->childCategories();
for (const QPlaceCategory &category : topLevelCategories)
    qDebug() << category.name();

如果我们提供了ID,则可以检索一个类别的子类别。

QList<QPlaceCategory> childCategories = manager->childCategories(pizza.categoryId());

保存一个类别

以下展示了如何保存一个类别

QPlaceCategory fastFood;

QPlaceCategory category;
category.setName("pizza");
/*QPlaceIdReply */ saveCategoryReply = manager->saveCategory(category);
connect(saveCategoryReply, &QPlaceIdReply::finished, this, &RequestHandler::handleSaveCategoryReply);

//we could have saved a category as a child by supplying a parent identifier.
saveCategoryReply = manager->saveCategory(category, fastFood.categoryId());
    ...
    ...
void handleSaveCategoryReply() {
    if (saveCategoryReply->error() == QPlaceReply::NoError) {
        qDebug() << "Saved category id =" << saveCategoryReply->id();
    }

    saveCategoryReply->deleteLater();
    saveCategoryReply = nullptr;
}

当类别被保存时,QPlaceManager可能会发出QPlaceManager::categoryAdded()或QPlaceManager::categoryUpdated()信号。然而,是否发出这些信号取决于提供者,从网络服务访问地点的管理者通常会发出这些信号,而访问本地存储的地点的管理者通常会发出。

删除一个类别

类别删除与删除地点非常相似

/* QPlaceIdReply * */removeCategoryReply = manager->removeCategory(place.placeId());
connect(removeCategoryReply, &QPlaceIdReply::finished, this, &RequestHandler::handleRemoveCategoryReply);
    ...
    ...
void handleRemoveCategoryReply() {
    if (removeCategoryReply->error() == QPlaceReply::NoError)
        qDebug() << "Removal of category identified by"
                 << removeCategoryReply->id() << "was successful";

    removeCategoryReply->deleteLater(); //discard reply
    removeCategoryReply = nullptr;
}

当删除类别时,QPlaceManager可能会发出QPlaceManager::categoryRemoved()信号。是否发出此信号取决于提供者。从网络服务访问地点的管理者通常会发出这些信号,而访问本地存储的地点的管理者通常会发出。

在管理者之间匹配地点

有时,您可能想交叉引用一个经理中的地点是否与另一个经理中的地点匹配。在以下情况下可能会出现这种情况:一个经理为地点提供只读访问权限(源经理),而另一个读/写经理(目标经理)用于保存从第一个经理中选定的收藏夹。在进行源经理的搜索时,我们可能想知道哪些已被“收藏”到目标经理,并可能显示比原始名称更具有个性化的收藏夹名称。

匹配机制在不同经理之间可能有所不同,但通常通过一个备选标识符完成。作为保存过程的一部分,源经理中的地点标识符被保存为目标经理中的一个备选标识符属性(目标经理有其自己的地点标识符方案)。在以下示例中,源经理来自“here”QGeoServiceProiver,因此作为保存过程的一部分,为保存到目标经理的地点设置了备选标识符属性x_id_here(当调用QPlaceManager::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

为了执行匹配,我们创建了一个QPlaceMatchRequest并将其分配给源经理的搜索结果。将使用QPlaceMatchRequest在目标经理上返回对应地点。我们还指定匹配参数,这是键值对。如前所述,这可能取决于经理,但通常键是QPlaceMatchRequest::AlternativeId,以表明我们通过备选id进行匹配,在这种情况下值将为x_id_here,它指定了我们使用哪个备选标识符属性进行匹配。

QPlaceMatchRequest request;
request.setResults(results);
QVariantMap parameters;
parameters.insert(QPlaceMatchRequest::AlternativeId, "x_id_here");
request.setParameters(parameters);
matchReply = manager->matchingPlaces(request);
    ...
    ...
void matchHandler() {
    if (matchReply->error() == QPlaceReply::NoError) {
        const auto places = matchReply->places();
        for (const QPlace &place : places) {
            if (place != QPlace())
                qDebug() << "Place is a favorite with name" << place.name();
            else
                qDebug() << "Place is not a favorite";
        }
    }

    matchReply->deleteLater();
    matchReply = nullptr;
}

地点类

数据类

QGeoAddress

表示QGeoLocation的地址

QGeoLocation

表示地点的基本信息

QPlace

表示关于地点的数据集

QPlaceAttribute

表示关于地点的通用属性信息

QPlaceCategory

表示一个与QPlace关联的类别

QPlaceContactDetail

表示联系电话号码或网站URL之类的联系细节

QPlaceContent

存储有关地点的内容

QPlaceIcon

表示一个图标

QPlaceProposedSearchResult

表示包含建议搜索的搜索结果

QPlaceRatings

包含有关地点的评分信息

QPlaceResult

表示包含地点的搜索结果

QPlaceSearchResult

搜索结果的基类

QPlaceSupplier

表示地点或与其关联的内容的供应商

QPlaceUser

表示单个用户

请求类

QPlaceContentRequest

表示内容请求的参数

QPlaceMatchRequest

用于从另一个经理中查找与第一个经理中的地点匹配的地点。它表示一系列请求参数

QPlaceSearchRequest

表示搜索请求的参数集

回复类

QPlaceContentReply

管理由QPlaceManager实例启动的内容检索操作

QPlaceDetailsReply

管理由QPlaceManager实例启动的地点详细信息检索操作

QPlaceIdReply

管理返回标识符的操作,如地点和类别的保存和删除操作

QPlaceMatchReply

管理由QPlaceManager实例启动的地点匹配操作

QPlaceReply

管理由QPlaceManager实例启动的操作,并作为更专业回复的基类

QPlaceSearchReply

管理由QPlaceManager实例启动的地点搜索操作

QPlaceSearchSuggestionReply

管理由QPlaceManager实例启动的搜索建议操作

管理器类

QPlaceManager

该接口允许客户端访问特定后端中存储的地点

QPlaceManagerEngine

为希望提供地点功能接入的QGeoServiceProvider插件实施者的接口

© 2024 The Qt Company Ltd. 本文档内的文档贡献属于各所有者的版权。本提供的文档根据自由软件基金会发布的GNU自由文档许可版本1.3的条款进行许可。Qt及其相关标志为芬兰以及全球其他国家的The Qt Company Ltd.商标。所有其他商标均为各自所有者的财产。