地点 (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);该请求属于异步操作,因此我们需要一个槽来处理请求的完成。在处理程序中,我们会检查是否存在错误,并确认搜索结果类型为“地点”。如果符合条件,我们即可获取该地点的一些核心详细信息。在槽结束时,我们会删除回复,因为它们仅限一次性使用。
voidhandleSearchReply() {
if(searchReply->error()==QPlaceReply::NoError) {
for(constQPlaceSearchResult&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(); // 丢弃回复
searchReply=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() {
if(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(), 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::ImageTypeQPlaceContent::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() {
if(savePlaceReply->error()==QPlaceReply::NoError)
qDebug() << savePlaceReply->id();
savePlaceReply->deleteLater();// 丢弃回复
savePlaceReply=nullptr;
}请注意,要保存已存在的地点,必须在 `QPlace::placeId()` 中填入正确的标识符。否则,如果该参数为空,将创建一个新地点;如果标识符不正确,则会覆盖错误的地点。
当位置被保存时,QPlaceManager 可能会发出 QPlaceManager::placedAdded() 或QPlaceManager::placeUpdated() 信号。但是,管理器是否发出这些信号取决于提供程序的具体实现:从 Web 服务访问位置的管理器通常不会发出这些信号,而访问本地存储位置的管理器通常会发出。
注意事项
目前,Places API 仅设计用于保存core 的详细信息。保存图片和评论等富内容,或供应商和评分等详细信息,均不属于受支持的使用场景。通常,管理器在保存时会忽略这些字段,如果这些字段被填充,可能会生成警告消息。
Places 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, &QPlaceIdReply::finished, this, &RequestHandler::handleRemovePlaceReply);
...
...
voidhandleRemovePlaceReply() {
if(removePlaceReply->error()==QPlaceReply::NoError)
qDebug() << "Removal of place identified by"
<< removePlaceReply->id()<< "操作成功";
removePlaceReply->deleteLater();// 丢弃回复
removePlaceReply=nullptr;
}当某个位置被移除时,QPlaceManager 可能会发出QPlaceManager::placeRemoved() 信号。管理器是否发出该信号取决于提供程序。通过 Web 服务访问位置的管理器通常不会发出这些信号,而访问本地存储位置的管理器通常会发出。
使用类别
类别是用于描述地点的关键词。例如,“公园”、“剧院”、“餐厅”。一个地点可以由多个类别描述,它既可以是公园,也可以是音乐演出场所,还可能是渡轮或公交车站。
要使用类别,必须先对其进行初始化。
/* QPlaceReply * */initCatReply = manager->initializeCategories();
connect(initCatReply, &QPlaceReply::finished, this, &RequestHandler::handleInitCatReply);
...
...
voidhandleInitCatReply() {
if(initCatReply->error()==QPlaceReply::NoError)
qDebug() << "Categories initialized";
else
qDebug() << "Failed to initialize categories";
initCatReply->deleteLater();
initCatReply=nullptr;
}在初始化完分类后,我们就可以使用这些分类函数了。
- QPlaceManager::childCategories()
- QPlaceManager::category()
- QPlaceManager::parentCategoryId()
- QPlaceManager::childCategoryIds();
要检索顶级分类,我们使用QPlaceManager::childCategories()函数,但无需提供分类标识符。
constQList<QPlaceCategory>topLevelCategories= manager->childCategories();
for(constQPlaceCategory&category: topLevelCategories)
qDebug() << category.name();如果我们确实提供了标识符,那么就可以获取该分类的子分类。
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);
//我们可以通过提供父类别标识符,将该类别保存为子类别。
saveCategoryReply= manager->saveCategory(category,fastFood.categoryId());
...
...
voidhandleSaveCategoryReply() {
if(saveCategoryReply->error()==QPlaceReply::NoError) {
qDebug() << "Saved category id =" << saveCategoryReply->id();
}
saveCategoryReply->deleteLater();
saveCategoryReply=nullptr;
}当类别被保存时,QPlaceManager 可能会发出QPlaceManager::categoryAdded() 或QPlaceManager::categoryUpdated() 信号。但是,管理器是否发出这些信号取决于提供程序的具体实现:通过 Web 服务访问位置的管理器通常不会发出这些信号,而访问本地存储位置的管理器通常会发出这些信号。
删除类别
删除类别与删除位置非常相似
/* QPlaceIdReply * */removeCategoryReply = manager->removeCategory(place.placeId());
connect(removeCategoryReply, &QPlaceIdReply::finished, this, &RequestHandler::handleRemoveCategoryReply);
...
...
voidhandleRemoveCategoryReply() {
if(removeCategoryReply->error()==QPlaceReply::NoError)
qDebug() << "Removal of category identified by"
<< removeCategoryReply->id()<< "操作成功";
removeCategoryReply->deleteLater();// 丢弃回复
removeCategoryReply=nullptr;
}当删除一个类别时,QPlaceManager 可能会发出QPlaceManager::categoryRemoved() 信号。管理器是否发出该信号取决于提供程序的具体实现。通过 Web 服务访问位置的管理器通常不会发出这些信号,而访问本地存储位置的管理器通常会发出。
不同管理器之间的地点匹配
有时您可能需要交叉核对,查看一个管理器中的地点是否与另一个管理器中的地点匹配。这种情况可能发生在:一个管理器(源管理器)提供对地点的只读访问,而另一个读写管理器(目标管理器)用于保存从源管理器中选定的收藏项。 在搜索源管理器时,我们可能希望了解哪些位置已被“收藏”到目标管理器中,并可能显示自定义的收藏名称而非原始名称。
不同管理器之间的匹配机制可能有所不同,但通常是通过替代标识符来实现的。在保存过程中,源管理器的地点标识符会被作为替代标识符属性保存在目标管理器中(目标管理器可能拥有自己的地点标识符方案)。 在下面的示例中,源管理器来自“here” QGeoServiceProvider,因此作为保存过程的一部分,会为保存到目标管理器中的地点设置一个替代标识符属性 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 ,表示我们正在按替代标识符进行匹配;在此情况下,值为x_id_here,用于指定我们正在使用哪个替代标识符属性进行匹配。
QPlaceMatchRequest request;
request.setResults(results);
QVariantMap parameters;
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();
else
qDebug() << "Place is not a favorite";
}
}
matchReply->deleteLater();
matchReply=nullptr;
}类在 Places 中的应用
数据类
表示 QGeoLocation 的地址 | |
表示有关某个位置的基本信息 | |
表示关于某个地点的一组数据 | |
表示关于某个地点的通用属性信息 | |
表示 QPlace 可以关联的类别 | |
表示联系方式,例如电话号码或网站网址 | |
包含有关地点的内容 | |
表示一个图标 | |
表示包含建议搜索结果的搜索结果 | |
存储有关地点的评分信息 | |
表示包含某个地点的搜索结果 | |
搜索结果的基类 | |
表示单个用户 |
请求类
表示内容请求的参数 | |
用于查找来自一个管理器的、与另一个管理器中的位置相匹配的位置。它代表一组请求参数 | |
表示搜索请求的一组参数 |
响应类
管理由 QPlaceManager 实例启动的内容检索操作 | |
管理由 QPlaceManager 实例启动的位置详情获取操作 | |
管理返回标识符的操作,例如地点和类别的保存及删除操作 | |
管理由 QPlaceManager 实例启动的地点匹配操作 | |
管理由 QPlaceManager 实例启动的操作,并作为更专门的响应的基类 | |
管理由 QPlaceManager 实例启动的地点搜索操作 | |
管理由 QPlaceManager 实例启动的搜索建议操作 |
管理类
允许客户端访问存储在特定后端中的地点的接口 | |
面向希望提供位置功能的 QGeoServiceProvider 插件实现者的接口 |
© 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.