 QGeoView)
真实地图库GIS/地图渲染的选型主要取决于你的应用场景是做地图数据渲染引擎还是开发桌面 GIS 应用或是三维数字地球。Mapnik老牌地图渲染引擎QGIS 库GIS 二次开发首选osgEarth三维地形渲染聚焦在二维场景,开源集成到Qt 桌面界面里显示-----QGeoView (栅格/瓦片地图)如果只需要嵌入简单的在线瓦片地图OSM、Google 等且希望快速集成这个库比较合适。它基于QGraphicsView实现接口设计参考了Google Maps API自带缩放、旋转和相机控制。文档和示例比较完整LGPL v3 协议近期仍有更新。AmonRaNet/QGeoView: QGeoView is a Qt / C widget for visualizing geographic data.QGeoView (QGV) 是一个基于Qt / C的地理数据可视化组件。让我为你梳理一下它的核心架构和特性。项目概览QGeoView是由 Andrey Yaroshenko (AmonRaNet) 开发的开源地理信息可视化控件采用LGPL v3许可证。它基于 Qt 的QGraphicsView框架设计目标是易用性和高性能。示例关于编译运行命令行编译如果你更喜欢命令行打开Qt 自带的命令行终端开始菜单里搜 Qt会有类似Qt 5.15.2 (MinGW 8.1.0 64-bit)的快捷方式必须要使用Qt自带的命令行终端然后执行D:\Qt\Qt5.12.8\5.12.8\mingw73_32cd D:\QtCode\QGeoView-master D:\QtCode\QGeoView-mastermkdir build D:\QtCode\QGeoView-mastercd build D:\QtCode\QGeoView-master\buildqmake ..\QGeoView.pro Info: creating stash file D:\QtCode\QGeoView-master\build\.qmake.stash D:\QtCode\QGeoView-master\buildmingw32-make遇到的问题D:\QtCode\QGeoView-master\build\samples\shared\release/libqgeoview-samples-shared.a(helpers.o):helpers.cpp:(.text0x53): undefined reference to _imp___ZNK3QGV7GeoRect6latTopEv D:\QtCode\QGeoView-master\build\samples\shared\release/libqgeoview-samples-shared.a(helpers.o):helpers.cpp:(.text0x5b): undefined reference to _imp___ZNK3QGV7GeoRect9latBottomEv D:\QtCode\QGeoView-master\build\samples\shared\release/libqgeoview-samples-shared.a(helpers.o):helpers.cpp:(.text0x73): undefined reference to _imp___ZNK3QGV7GeoRect8lonRightEv D:\QtCode\QGeoView-master\build\samples\shared\release/libqgeoview-samples-shared.a(helpers.o):helpers.cpp:(.text0x7b): undefined reference to _imp___ZNK3QGV7GeoRect7lonLeftEv D:\QtCode\QGeoView-master\build\samples\shared\release/libqgeoview-samples-shared.a(helpers.o):helpers.cpp:(.text0x110): undefined reference to _imp___ZN3QGV6GeoPosC1Edd D:\QtCode\QGeoView-master\build\samples\shared\release/libqgeoview-samples-shared.a(helpers.o):helpers.cpp:(.text0x229): undefined reference to _imp___ZNK3QGV6GeoPos8latitudeEv D:\QtCode\QGeoView-master\build\samples\shared\release/libqgeoview-samples-shared.a(helpers.o):helpers.cpp:(.text0x237): undefined reference to _imp___ZNK3QGV6GeoPos9longitudeEv D:\QtCode\QGeoView-master\build\samples\shared\release/libqgeoview-samples-shared.a(helpers.o):helpers.cpp:(.text0x26c): undefined reference to _imp___ZN3QGV7GeoRectC1Edddd D:\QtCode\QGeoView-master\build\samples\shared\release/libqgeoview-samples-shared.a(helpers.o):helpers.cpp:(.text0x427): undefined reference to _imp___ZN3QGV17setNetworkManagerEP21QNetworkAccessManager collect2.exe: error: ld returned 1 exit statusD:\QtCode\QGeoView-master\build\samples\shared\release/libqgeoview-samples-shared.a(helpers.o):helpers.cpp:(.text0x53): undefined reference to _imp___ZNK3QGV7GeoRect6latTopEv问题根因分析basic.pro中两个 pri 文件的包含顺序是include(../lib.pri) # 先加 -lqgeoview include(../shared.pri) # 后加 -lqgeoview-samples-shared这导致最终链接命令中库的顺序为-lqgeoview -lqgeoview-samples-shared。问题在于链接顺序qgeoview-samples-shared是静态库它依赖qgeoviewDLL的符号。GNU 链接器是单遍扫描的当它先处理-lqgeoview时helpers.o还没被拉入所以没有对 QGV 符号的未定义引用等处理到-lqgeoview-samples-shared拉入helpers.o时产生了新的_imp__QGV::*未定义引用但链接器已经不会回头再去qgeoview里找了于是报undefined reference。正确的顺序应该是被依赖的库放在后面即-lqgeoview-samples-shared -lqgeoview所有 15 个示例的 .pro 文件都有相同的错误顺序lib.pri在前shared.pri在后。这导致-lqgeoview排在-lqgeoview-samples-shared之前链接顺序错误。修复方案将每个示例 .pro 中两个 include 的顺序对调让shared.pri静态库依赖方在前lib.priQGeoView DLL被依赖方在后。这样链接顺序变为-lqgeoview-samples-shared -lqgeoviewGNU 链接器就能正确解析符号。这样链接命令变为-lqgeoview-samples-shared -lqgeoview符合依赖方在前、被依赖方在后的 GNU 链接规则。再讲讲上面的链接错误吧我不理解先理解三个角色角色是什么谁依赖谁basic可执行程序最终要生成的.exe依赖 sharedshared静态库.ahelpers.o、rectangle.o等打包在一起依赖 qgeoviewqgeoview动态库.dllQGV 的核心库包含GeoPos、GeoRect等类的实现无依赖依赖链basic → shared → qgeoview静态库的惰性特性静态库.a本质上是一堆.o文件的压缩包。链接器处理它时有一个关键行为只有当链接器已经遇到了未定义符号才会从静态库里提取对应的.o文件。也就是说静态库里的.o文件不会自动全部拉进来而是按需提取。错误顺序下的链接过程修复前basic.pro的 include 顺序是include(../lib.pri) # → 链接命令先加 -lqgeoview include(../shared.pri) # → 链接命令后加 -lqgeoview-samples-shared最终链接命令等价于g main.o mainwindow.o -lqgeoview -lqgeoview-samples-shared -o basic.exe链接器从左到右单遍扫描过程如下第1步处理 main.o, mainwindow.o → 发现未定义符号Helpers::xxx, Rectangle::xxx来自 shared 库 → 记住这些未定义引用 第2步处理 -lqgeoviewDLL → 当前未定义引用是 Helpers::xxx, Rectangle::xxx → qgeoview 里没有这些符号它们属于 shared 库 → 所以 qgeoview 被完全跳过什么都没拉进来 → 未定义引用仍然是 Helpers::xxx, Rectangle::xxx 第3步处理 -lqgeoview-samples-shared静态库 → 当前未定义引用是 Helpers::xxx, Rectangle::xxx → 从 shared 里拉出 helpers.o、rectangle.o 来解决这些引用 → ✅ Helpers::xxx, Rectangle::xxx 解决了 → ❌ 但 helpers.o 内部又引用了 QGV::GeoPos、QGV::GeoRect 等符号 → 这些新的未定义引用产生了但链接器已经走过了 -lqgeoview → 链接器不会回头 → undefined reference 报错所以说这样写实际上不会引用到库qgeoview而库qgeoview-samples-shared依赖它。正确顺序下的链接过程修复后顺序对调g main.o mainwindow.o -lqgeoview-samples-shared -lqgeoview -o basic.exe第1步处理 main.o, mainwindow.o → 未定义引用Helpers::xxx, Rectangle::xxx 第2步处理 -lqgeoview-samples-shared静态库 → 拉出 helpers.o、rectangle.o 解决 Helpers/Rectangle 的引用 → helpers.o 内部产生新的未定义引用QGV::GeoPos、QGV::GeoRect 等 → 这些引用被记住等待后续库解决 第3步处理 -lqgeoviewDLL → 当前未定义引用是 QGV::GeoPos、QGV::GeoRect 等 → qgeoview 正好提供这些符号 ✅ → 所有引用解决链接成功 一句话总结GNU 链接器从左到右只扫一遍。静态库按需提取.o提取后产生的新引用只能靠后面的库解决。所以依赖方shared必须放在被依赖方qgeoview前面。为什么有_imp_前缀错误信息里的_imp___ZNK3QGV7GeoRect6latTopEv中_imp_前缀 这是从DLL导入的符号因为QGV_LIB_DECL在没定义QGV_EXPORT时展开为Q_DECL_IMPORT__ZNK3QGV7GeoRect6latTopEv C 名称修饰name mangling还原后就是QGV::GeoRect::latTop()const这说明helpers.cpp编译时看到的是Q_DECL_IMPORT导入模式链接时需要从qgeoview.dll的导入库.dll.a中找到这些符号。顺序错了就找不到。