安装环境搭建

QGIS的二次开发支持Windows和Linux下进行,这里分别介绍一下环境搭建。

Windows下环境搭建(待详细介绍)

MSVC 2022 安装

官网下载VS2022,安装时选择C++的开发环境。

Qt安装

在线安装Qt即可,最新的QGIS 3.40 版本下载的Qt库是Qt6,需要安装Qt6的开发环境。

QGIS dev开发环境安装

Windows下环境搭建比较简单,直接下载QGIS的在线安装包OSGeo4W进行安装-dev版本的即可。

Ubuntu22下环境搭建

(可选)WSl安装Ubuntu 22

我是直接在Windows上安装的WSL2,直接在Windows上安装Ubuntu22.04即可。

wsl --install Ubuntu-22.04

安装系统依赖

参考:QGIS官方安装说明

sudo apt-get update
sudo apt-get install bison build-essential ca-certificates ccache cmake cmake-curses-gui dh-python expect flex flip gdal-bin git graphviz grass-dev libdraco-dev libexiv2-dev libexpat1-dev libfcgi-dev libgdal-dev libgeos-dev libgsl-dev libpdal-dev libpq-dev libproj-dev libprotobuf-dev libqca-qt5-2-dev libqca-qt5-2-plugins libqscintilla2-qt5-dev libqt5opengl5-dev libqt5serialport5-dev libqt5sql5-sqlite libqt5svg5-dev libqt5webkit5-dev libqt5xmlpatterns5-dev libqwt-qt5-dev libspatialindex-dev libspatialite-dev libsqlite3-dev libsqlite3-mod-spatialite libyaml-tiny-perl libzip-dev libzstd-dev lighttpd locales ninja-build nlohmann-json3-dev ocl-icd-opencl-dev opencl-headers pandoc pdal pkgconf poppler-utils protobuf-compiler pyqt5-dev pyqt5-dev-tools pyqt5.qsci-dev python3-all-dev python3-autopep8 python3-dev python3-gdal python3-jinja2 python3-lxml python3-mock python3-nose2 python3-owslib python3-packaging python3-plotly python3-psycopg2 python3-pygments python3-pyproj python3-pyqt5 python3-pyqt5.qsci python3-pyqt5.qtmultimedia python3-pyqt5.qtpositioning python3-pyqt5.qtserialport python3-pyqt5.qtsql python3-pyqt5.qtsvg python3-pyqt5.qtwebkit python3-pyqtbuild python3-sip python3-termcolor python3-yaml qt3d-assimpsceneimport-plugin qt3d-defaultgeometryloader-plugin qt3d-gltfsceneio-plugin qt3d-scene2d-plugin qt3d5-dev qtbase5-dev qtbase5-private-dev qtkeychain-qt5-dev qtmultimedia5-dev qtpositioning5-dev qttools5-dev qttools5-dev-tools sip-tools spawn-fcgi xauth xfonts-100dpi xfonts-75dpi xfonts-base xfonts-scalable xvfb

设置 ccache(可选,但推荐)

您还应该设置 ccache 以加快编译时间:

cd /usr/local/bin
sudo ln -s /usr/bin/ccache gcc
sudo ln -s /usr/bin/ccache g++

下载QGIS源码

mkdir ~/dev
cd ~/dev
git clone https://github.com/qgis/QGIS.git
cd QGIS
# 切换到3.40分支
git checkout release-3_40

启动编译

这里是直接安装到系统目录下,需要sudo ninja install权限。 如果需要安装到指定位置,cmake命令需要添加参数:-D CMAKE_INSTALL_PREFIX=${HOME}/apps

mkdir ~/apps
mkdir build
cd build
cmake -G Ninja -D WITH_3D=false ..

# 如果需要安装到用户目录下
# cmake -G Ninja -D WITH_3D=false -D CMAKE_INSTALL_PREFIX=${HOME}/apps ..

构建

ninja
sudo ninja install # 如果是安装到用户目录下,不需要带sudo

创建Qt项目

项目结构

MapView/
├── CMakeLists.txt
├── main.cpp
├── mainwindow.cpp
├── mainwindow.h
├── mainwindow.ui
├── resources.qrc

CMakeLists.txt 配置

可参考下面的cmake配置文件,如果QGIS是安装到用户目录下,需要指定QGIS的include和lib目录

cmake_minimum_required(VERSION 3.14)
project(MapView VERSION 0.1 LANGUAGES CXX)

# Set build type to Release
set(CMAKE_BUILD_TYPE Release)

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Xml PrintSupport)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Xml PrintSupport)

# QGIS configuration - use system installation
find_package(PkgConfig QUIET)
if(PkgConfig_FOUND)
    pkg_check_modules(QGIS QUIET qgis)
endif()

# Find QGIS libraries from system installation
find_library(QGIS_CORE_LIBRARY NAMES qgis_core)
find_library(QGIS_GUI_LIBRARY NAMES qgis_gui)
find_library(QGIS_APP_LIBRARY NAMES qgis_app)
find_library(QGIS_NATIVE_LIBRARY NAMES qgis_native)
find_library(QGIS_ANALYSIS_LIBRARY NAMES qgis_analysis)

# Check if QGIS is available
if(QGIS_CORE_LIBRARY)
    message(STATUS "QGIS libraries found in system")
    set(QGIS_FOUND TRUE)
    
    # Try to find QGIS include directory
    find_path(QGIS_INCLUDE_DIR qgis.h
        PATHS /usr/include/qgis /usr/local/include/qgis
        PATH_SUFFIXES qgis
    )
    
    if(QGIS_INCLUDE_DIR)
        message(STATUS "QGIS include directory: ${QGIS_INCLUDE_DIR}")
    else()
        message(WARNING "QGIS include directory not found")
    endif()
else()
    message(WARNING "QGIS libraries not found in system - building without QGIS support")
    set(QGIS_FOUND FALSE)
endif()

# Automatically collect all source files
file(GLOB_RECURSE PROJECT_SOURCES
    "*.cpp"
    "*.h"
    "*.ui"
    "*.qrc"
)

# Filter out build directory if it exists
list(FILTER PROJECT_SOURCES EXCLUDE REGEX "${CMAKE_BINARY_DIR}/.*")

# Print found sources for debugging
message(STATUS "Found source files: ${PROJECT_SOURCES}")

if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
    qt_add_executable(MapView
        MANUAL_FINALIZATION
        ${PROJECT_SOURCES}
    )
else()
    add_executable(MapView
        ${PROJECT_SOURCES}
    )
endif()

# Add QGIS support if available
if(QGIS_FOUND)
    if(QGIS_INCLUDE_DIR)
        target_include_directories(MapView PRIVATE ${QGIS_INCLUDE_DIR})
    endif()
    target_compile_definitions(MapView PRIVATE
        _USE_MATH_DEFINES
        QGIS_ENABLED
    )
else()
    target_compile_definitions(MapView PRIVATE _USE_MATH_DEFINES)
endif()

# Link Qt libraries
target_link_libraries(MapView PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Xml Qt${QT_VERSION_MAJOR}::PrintSupport)

# Link QGIS libraries if available
if(QGIS_FOUND)
    target_link_libraries(MapView PRIVATE
        ${QGIS_CORE_LIBRARY}
        ${QGIS_GUI_LIBRARY}
        ${QGIS_APP_LIBRARY}
        ${QGIS_NATIVE_LIBRARY}
        ${QGIS_ANALYSIS_LIBRARY}
    )

    # Set RPATH to find QGIS libraries at runtime (system paths)
    set_target_properties(MapView PROPERTIES
        BUILD_WITH_INSTALL_RPATH TRUE
        INSTALL_RPATH_USE_LINK_PATH TRUE
    )
endif()

if(${QT_VERSION} VERSION_LESS 6.1.0)
    set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.example.MapView)
endif()
set_target_properties(MapView PROPERTIES
    ${BUNDLE_ID_OPTION}
    MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
    MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
    MACOSX_BUNDLE TRUE
    WIN32_EXECUTABLE TRUE
)

if(QT_VERSION_MAJOR EQUAL 6)
    qt_finalize_executable(MapView)
endif()

主要代码片段

main.cpp

#include "mainwindow.h"

#include "qgsapplication.h"
#include <QApplication>

int main(int argc, char *argv[]) {
  QgsApplication a(argc, argv, true);
  a.init();
  a.initQgis();
  MainWindow w;
  w.show();
  return a.exec();
}

mainwindow.cpp

#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include "mapcanvas/mapcanvas.h"
#include "qgsmaptoolpan.h"
#include <qnamespace.h>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::MainWindow) {
  ui->setupUi(this);
  setWindowTitle(QStringLiteral("软件标题"));
  // 自定义地图类,实现自己的地图功能
  MapCanvas *mapcanvas = new MapCanvas(this);
  // 地图画布设置为黑色
  mapcanvas->setCanvasColor(Qt::black);
  // 这一步是把MapCanvas放到窗口布局的下面,这样可以实现Qt的控件叠加显示在地图上面
  ui->gridLayout->addWidget(mapcanvas, 0, 0, 1, 1);
  // mapcanvas->lower();

  // 设置地图工具,默认自带拖拽移动和缩放,可创建新的类实现自己想要的操作逻辑
  QgsMapToolPan *maptool = new QgsMapToolPan(mapcanvas);
  mapcanvas->setMapTool(maptool);
}

MainWindow::~MainWindow() { delete ui; }

mapcanvas.cpp

#include "mapcanvas.h"

QgsRasterLayer *MapCanvas::getInitRasterLayer(const QString &url,
                                              const QString &name) {
  QgsRasterLayer *raster = new QgsRasterLayer(url, name);
  //   raster->setCrs(QgsCoordinateReferenceSystem::fromEpsgId(3857));
  this->setExtent(raster->extent());

  auto layers = this->layers();
  layers.append(raster);
  this->setLayers(layers);

  this->zoomToFullExtent();
  this->refresh();
  return raster;
}

MapCanvas::~MapCanvas() {
  if (_qgsproject) {
    _qgsproject->removeAllMapLayers();
  }
}

MapCanvas::MapCanvas(QWidget *parent) : QgsMapCanvas(parent) {
  _qgsproject = QgsProject::instance();
  // 这是一个我自己写的生成xml文件的类,用于生成qgis需要的xml文件
  XmlGenerator xmlGen;
  xmlGen.generateXmlFiles();
  // 这里是两个图层,图层可以叠加显示,也可以自己写逻辑,切换显示
  QString street_file = xmlGen.GetStreetXmlFile();
  QString satellite_file = xmlGen.GetSatelliteXmlFile();
  //   _street_layer = getInitRasterLayer(street_file, "street");
  _satellite_layer = getInitRasterLayer(satellite_file, "satellite");
  //   _qgsproject->addMapLayer(_street_layer);
  // 把图层添加到qgsproject中
  _qgsproject->addMapLayer(_satellite_layer);
  setProject(_qgsproject);
}

未完待续

参考效果

image.png