地点(C++)

地图与导航

地点应用程序接口(Places 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);

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

voidhandleSearchReply() {如果searchReply->error()==QPlaceReply::NoError) {for(constQPlaceSearchResult&result: searchReply->results()) {if(result.type()==::PlaceResult) {如果(result.type()==::PlaceResult() QPlaceSearchResult::PlaceResult) { QPlaceResultplaceResult=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 replysearchReply=nullptr; }

注意:根据所选插件后台的不同,搜索结果中可能包含有更多详细信息的地点,这些详细信息可按地点逐一获取。要获取这些其他详细信息,请参阅获取地点详细信息

建议

可通过QPlaceSearchRequest::setRecommendationId() 提供一个地点 ID 来获取推荐信息。任何与给定地点相似的地点都会被检索到。

分页

如果插件支持分页,则可在搜索请求中提供 limit 参数。

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);

我们可以如下所示处理内容请求。

voidhandleImagesReply() {如果contentReply->error()==QPlaceReply::NoError) {const autocontent=  contentReply->content();for(autoiter=content.cbegin(),end=content.cend(); iter!=end;++iter) {            qDebug() << "Index: " << iter.key();
           QPlaceImageimage=iter.value();            qDebug() << image.url();
            qDebug() << image.mimeType();
        }//如果索引无关紧要,也可以采用这种方法 for(const QPlaceImage &image: contentReply->content()) {            qDebug() << image.url();
            qDebug() << image.mimeType();
        place.insertContent(contentReply->request(). contentType();place. setTotalContentCount(contentReply->request().contentType();place. setTotalContentCount(contentReply->request().contentType().contentReply->request().contentType(),contentReply->content()); place.setTotalContentCount(contentReply->request().contentType(),  contentReply->totalCount()); } contentReply->deleteLater(); contentReply=nullptr; }

值得注意的是,QPlaceContentReply, 中的结果是QPlaceContent::Collection ,而 本质上是QMap<int,QPlaceContent>。在这种情况下,关键字int 是内容的索引,而值就是内容本身。根据 Content 的实现方式,可以按以下方式转换内容类型

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);

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

voidhandleSuggestionReply() {if(suggestionReply->error()==QPlaceReply::NoError) {for(constQString&suggestion: suggestionReply->suggestions())            qDebug() << suggestion;
    } suggestionReply->deleteLater();//丢弃回复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);

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

voidhandleSavePlaceReply() {如果savePlaceReply->error()==QPlaceReply::NoError)        qDebug() << savePlaceReply->id();

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

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

保存位置时,QPlaceManager 可能会发出 QPlaceManager::placedAdded() 或QPlaceManager::placeUpdated() 信号。不过,管理器是否这样做取决于提供商,从网络服务访问位置的管理器一般不会发出这些信号,而访问本地存储位置的管理器一般会发出这些信号。

注意事项

地点 API 目前仅用于保存core 详细信息。不支持保存图片和评论等丰富内容,也不支持保存供应商和评级等详细信息。通常情况下,管理器在保存时会忽略这些字段,如果填充了这些字段,可能会产生警告信息。

地点 API 仅支持保存以下核心详细信息

  • 名称
  • 地点 ID
  • 地点
  • 联系方式
  • 图标
  • 类别(描述地点的标签式名称)
  • 可见性范围

提供商可能只支持其中的一个子集。详情请查看插件文档

Places 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, &RequestHandler::finished,this, &RequestHandler::handleRemovePlaceReply);......QPlaceIdReply::finished, this, &RequestHandler::handleRemovePlaceReply); ... ...voidhandleRemovePlaceReply() {if(removePlaceReply->error()==QPlaceReply::NoError)        qDebug() << "Removal of place identified by"
                <<  removePlaceReply->id()<< "was successful"; removePlaceReply->deleteLater();//discardreply removePlaceReply=nullptr; }

删除地点时,QPlaceManager 可能会发出QPlaceManager::placeRemoved() 信号。管理器是否这样做取决于提供商。从网络服务访问位置的管理程序通常不会发出这些信号,而访问本地存储位置的管理程序通常会发出这些信号。

使用类别

类别是可以描述地点的关键字。例如,"公园"、"剧院"、"餐厅"。一个地方可以用很多类别来描述,它可以是公园、音乐场所、渡口或巴士站。

要使用类别,首先必须对其进行初始化。

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

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

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

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

()函数 QList<QPlaceCategory>topLevelCategories=  manager->childCategories();for(constQPlaceCategory类别: topLevelCategories)    qDebug() << category.name();

如果我们提供了一个标识符,那么我们就可以检索一个类别的子类别。

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

保存类别

下面显示了如何保存类别

QPlaceCategory保存类别QPlaceCategorycategory; category.setName("pizza");/*QPlaceIdReply */saveCategoryReply=  manager->saveCategory(category); connect(saveCategoryReply, &RequestHandler::finished,this, &RequestHandler::handleSaveCategoryReply);//我们可以将类别保存为 fastFoodQPlaceIdReplysaveCategoryReply=manager->saveCategory(category,fastFood.categoryId()); ... ...voidhandleSaveCategoryReply() {if(saveCategoryReply->error()== **QPlaceIdReply */ saveCategoryReply = manager->saveCategory(category); connect(saveCategoryReply,&RequestHandler::finished, this, &RequestHandler::handleSaveCategoryReply);//we could have saved a category as a child by supplying a parent identifier.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, &RequestHandler::finished,this, &RequestHandler::handleRemoveCategoryReply);......QPlaceIdReplyvoid  handleRemoveCategoryReply(){if(removeCategoryReply->error()== *... QPlaceReply::NoError)        qDebug() << "Removal of category identified by"
                <<  removeCategoryReply->id()<< "was successful"; removeCategoryReply->deleteLater();//discardreply removeCategoryReply=nullptr; }

删除类别时,QPlaceManager 可能会发出QPlaceManager::categoryRemoved() 信号。管理器是否这样做取决于提供商。从网络服务访问位置的管理程序通常不会发出这些信号,而访问本地存储位置的管理程序通常会发出这些信号。

在管理器之间匹配位置

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

不同管理器的匹配机制可能会有所不同,但通常都是通过替代标识符来实现的。作为保存过程的一部分,原点管理器中的地点标识符会作为替代标识符属性保存到目的地管理器中(目的地管理器可以有自己的地点标识符方案)。在下面的示例中,原点管理器来自 QGeoServiceProider 的 "here",因此作为保存过程的一部分,在调用QPlaceManager::compatiblePlace() 时,会为保存到目的地管理器的地点设置一个替代标识符属性 x_id_here

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 ,表示我们通过替代标识符进行匹配,在这种情况下,值是 x_id_here,表示我们使用哪个替代标识符属性进行匹配。

QPlaceMatchRequestrequest;request.setResults(results);QVariantMapparameters; parameters.insert(QPlaceMatchRequest::AlternativeId, "x_id_here"); request.setParameters(parameters); matchReply=  manager->matchingPlaces(request); ... ...voidmatchHandler() {if(matchReply->error()==QPlaceReply::NoError) {const autoplaces=  matchReply->places();for(constQPlace&place: places) {if(place!= ()) QPlace())                qDebug() << "Place is a favorite with name" << place.name();
           不然                qDebug() << "Place is not a favorite";
        } matchReply->deleteLater(); matchReply=nullptr; }

位置中的类

数据类

QGeoAddress

代表 QGeoLocation 的地址

QGeoLocation

代表一个地点的基本信息

QPlace

代表一个地点的数据集

QPlaceAttribute

代表一个地点的通用属性信息

QPlaceCategory

代表一个 QPlace 可以关联的类别

QPlaceContactDetail

代表联系详情,如电话号码或网址

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 插件实现者提供的接口

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