Shapefile 为 OGR 所支持的最重要的数据格式之一,自然可以被 QGIS 加载。那么该如何显示Shapefile呢?
一、先上代码
#include <qgsapplication.h>
#include <qgsproviderregistry.h>
#include <qgsmapcanvas.h>
#include <qgsvectorlayer.h>
int main(int argc, char **argv)
{
	// 创建 QgsApplication 实例
	QgsApplication app(argc, argv, true);
	// 设置并检查数据插件目录
	QgsProviderRegistry::instance("D:/OSGeo4W/apps/qgis-ltr/plugins");
	// 控制台打印已载入的插件目录
	qDebug() << "QGIS data providers loaded:" << QgsProviderRegistry::instance()->providerList();
	// 设置 GDAL 数据目录环境变量
	qputenv("GDAL_DATA", "D:\\OSGeo4W\\apps\\gdal\\share\\gdal");
	// 创建 QgsCanvas 画布实例
	QgsMapCanvas c;
	// 从磁盘 .shp 文件创建矢量图层
	QgsVectorLayer* pVectorLayer = new QgsVectorLayer(u8"E:\\TestImage\\全国省界\\全国省界.shp", u8"省界");
	// 确认图层是否创建成功
	qDebug() << "Is layer valid:" << pVectorLayer->isValid();
	// 将图层添加到画布上
	c.setLayers(QList<QgsMapLayer*>() << pVectorLayer);
	// 设置画布窗体标题并显示画布
	// 画布本身是 QWidget 的子类,因此可以承担 QWidget 的所有操作
	c.setWindowTitle(u8"QGIS 二次开发:画布");
	c.show();
	// 缩放到图层的空间范围
	c.zoomToFullExtent();
	// 启动 QgsApplication 实例
	return app.exec();
}
 
二、效果图

三、代码讲解
(一)
// 创建 QgsApplication 实例
QgsApplication app(argc, argv, true); 
需要头文件<qgsapplication.h>
参见QGIS API Documentation: QgsApplication Class Reference
该类继承自QApplication,提供对QGIS特定资源(如主题路径、数据库路径等)的访问。
构造函数接受 5 个参数。其中 3 个是必备参数。前两个参数传入 main 函数的两个参数即可,第三个参数表示是否激活图形界面 GUI,一般设置为 true,除非你想做一个命令行的程序,如单纯用于数据处理,无需界面的程序。这里我们设置为 true。 
(二)
// 设置并检查数据插件目录
QgsProviderRegistry::instance("D:/OSGeo4W/apps/qgis-ltr/plugins"); 
需要头文件<qgsproviderregistry.h>
官方文档QGIS API Documentation: QgsProviderRegistry Class Reference
参数如下,pluginPath为数据插件的路径
QgsProviderRegistry * QgsProviderRegistry::instance(const QString & pluginPath = QString())	
 
数据驱动插件为一系列的动态链接库文件,存放于 QGIS 开发包的 plugins 目录下
// 控制台打印已载入的插件目录
qDebug()<<"QGIS data providers loaded:"<<QgsProviderRegistry::instance()->providerList(); 
 调用 QgsProviderRegistry 的成员函数 providerList() 可以返回一个存放所有支持的数据驱动插件的 QStringList 字符串列表,可以用于 debug。
参见QGIS API Documentation: QgsProviderRegistry Class Reference
(三)
// 设置 GDAL 数据目录环境变量
qputenv("GDAL_DATA", "D:\\OSGeo4W\\apps\\gdal\\share\\gdal"); 
随后程序会检测 GDAL 的环境变量 GDAL_DATA 是否设置。该环境变量为一个目录,存放 GDAL 所需的资源和数据文件等。利用 Qt 提供的全局函数 qputenv() 可以方便的设置环境变量而无需修改操作系统设置,该环境变量仅在当前程序中生效。
参见官方文档 https://doc.qt.io/qt-5/qtglobal.html#qputenv
(四)
// 创建 QgsCanvas 画布实例
QgsMapCanvas c; 
头文件<qgsmapcanvas.h>
它是 Qt 用于描述图形场景的 QGraphicsView 的子类,用于显示GIS类型的数据。
官方文档 QGIS API Documentation: QgsMapCanvas Class Reference
(五)
// 从磁盘 .shp 文件创建矢量图层
QgsVectorLayer* pVectorLayer = new QgsVectorLayer(u8"E:\\TestImage\\全国省界\\全国省界.shp", u8"省界"); 
头文件<qgsvectorlayer.h>
创建 QgsVectorLayer 的实例。该类在 QGIS 中描绘一个矢量图层,是 QgsMapLayer 的子类。
继承关系如下

构造函数原型为
QgsVectorLayer::QgsVectorLayer	(
    const QString & path = QString(),
    const QString & baseName = QString(),
    const QString & providerLib = "ogr",
    const QgsVectorLayer::LayerOptions & options = QgsVectorLayer::LayerOptions() 
)	 
path为参数的路径或url,baseName为在图例中展示的图层名称,
参见QGIS API Documentation: QgsVectorLayer Class Reference
图层创建完成后,可调用 isValid() 方法查看是否创建成功。
// 确认图层是否创建成功
qDebug() << "Is layer valid:" << pVectorLayer->isValid(); 
该方法位于QgsVectorLayer的父类QgsMapLayer中,返回图层的状态,创建成功则返回True,否则返回False。如果返回False,则可以通过QgsMapLayer的error()方法进步查看错误详情。
(六)
// 将图层添加到画布上
c.setLayers(QList<QgsMapLayer*>() << pVectorLayer); 
图层创建成功后,将其添加到画布。调用画布类 QgsMapCanvas 的 setLayers() 方法即可,该方法会设置一个将在画布上面显示的图层列表。
函数原型如下,参见 QGIS API Documentation: QgsMapCanvas Class Reference
void QgsMapCanvas::setLayers(const QList< QgsMapLayer * > & layers)	
 
该方法接受一个图层基类 QgsMapLayer 指针的列表。通常情况下,图层越位于列表前面(即下标越小),绘制顺序越靠后(即越靠近观察者)。
(七)
// 设置画布窗体标题并显示画布
// 画布本身是 QWidget 的子类,因此可以承担 QWidget 的所有操作
c.setWindowTitle(u8"QGIS 二次开发:画布");
c.show(); 
在 Qt 中,只要是 QWidget 及其子类都可以作为单独的程序窗体处理。QgsMapCanvas 作为 QGraphicsView 的子类,当然也是QWidget的子类,我们可以使用QWidget的公共槽函数setWindowTitle()为其设置窗口标题,然后使用show()让其像普通的窗口一样显示出来。
(八)
// 缩放到图层的空间范围
c.zoomToFullExtent(); 
调用QgsMapCanvas的zoomToFullExtent(),这一步操作会让 QgsMapCanvas 缩放到内部所有可见图层的完整范围,就是让所有可见图层都完整地显示出来。
参见 QGIS API Documentation: QgsMapCanvas Class Reference
(九)
// 启动 QgsApplication 实例
return app.exec(); 
 最后,启动 QgsApplication (即 QApplication)。exec() 方法位于QgsApplication的父类QApplication中,目的是让程序进入主循环。主循环被打断后(如所有窗口关闭),程序结束。
参见官方文档 QApplication Class | Qt Widgets 5.15.14
参考文章 文章页 | mriiiron's blog

















