最近接到任务是进行QGIS符号配置界面的开发,由于当时把QGIS集成到我们桌面三维GIS平台时用到的QGIS版本是2.18.5(比较坑的一个版本,集成之后发现不少bug,补bug补了好久,换版本再集成不是那么容易的,无奈沿用至今),所以就还选用这个版本,毕竟最后还是要集成到三维平台里。其实各个版本核心功能差别不大。
其实符号配置这个网上都有,直接拿来用完成简单任务不成问题,但是个人觉得对深入学习QGIS并无多大助益,要想学好必须要深入源码进行研究。这里还想再说一点,QGIS不仅是学习开源GIS的最佳平台,还是学习Qt极好的选择,只不过对于非GIS专业的同学来说有点吃力,因为在研究源码里Qt相关内容时,要有意识的去掉GIS的内容。
我们一般配置样式的步骤就是双击图层,弹出属性对话框,调整到样式界面,开始配置符号,如下图
图层属性对话框对应的类是QgsVectorLayerProperties隶属于APP模块。其继承自QgsVectorLayerPropertiesBase,其实就是一个ui文件。如下图
可以看到右侧是空白,其实是一个QStackWidget,根据点击左边的list的item不同,显示出不同的Widget。
当我们点击style选项卡时,出现如下界面
右面这个的组成分为两部分,第一是不能上下滑动的部分,它的类名叫QgsRendererV2PropertiesDialog,还有一部分是滑动的部分,其本质是嵌套在一个QStackWidget上的,它和上面的Comobox关联,根据符号渲染类型的不同,显示对应的widget。这些widget都继承自QgsRendererV2Widget,根据不同的符号渲染类型又派生出QgsSingleSymbolRendererV2Widget、Qgs25DRendererWidget、QgsCategorizedSymbolRendererV2Widget等。由于本次重点研究的是单一符号配置,所以关注焦点放在QgsSingleSymbolRendererV2Widget,进一步查看源码发现,并结合ui文件发现,其中的一个成员QgsSymbolV2SelectorWidget正是整个符号配置对话框的核心。那它怎么用呢?打开qgisapp.cpp尝试搜索一下这个类,发现没找到。后来偶然发现,在QgsSymbolV2SelectorWidget文件里还有一个类QgsSymbolV2SelectorDialog,这个类完全就是把QgsSymbolV2SelectorWidget包了一下,那这个类有没有呢,还在qgisapp.cpp的文件里,果然搜到了。实在是不得不佩服QGIS的作者们,这个类用法极其简单,而且与其他类耦合程度很低,完全就是一个工具类的感觉,只要构造一下,传入需要的参数,接下来你就不用管了,里面都给你做好了,你直接显示就行。另外,QgsSymbolV2SelectorWidget里面包含了QgsSymbolV2,QgsSymbolV2也很独立。特别符合GIS的相关概念,QgsSymbolV2就是GIS中符号这一概念在QGIS中的体现。下面展示了QGIS符号配置界面相关结构图
对话框创建顺序图如下
最后再贴出完整的代码,时间仓促,匆匆写了一个测试代码,目的是实现功能,后续肯定要优化。
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
#include
#include
#include
class QgsLayerTreeMapCanvasBridge;
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void showMap();
public slots:
void extentChanged();
void openStyleDlg(QModelIndex index);
private:
Ui::MainWindow *ui;
QgsMapCanvas m_Canvas;
QgsLayerTreeView m_Tree;
QgsLayerTreeMapCanvasBridge* m_bridge;
};
#endif // MAINWINDOW_H
#include "MainWindow.h"
#include "ui_MainWindow.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
,m_bridge(NULL)
{
ui->setupUi(this);
m_Canvas.setParent(this->centralWidget());//此句一定要在ui->setupUi(this);之后
QSplitter* sp = new QSplitter(Qt::Horizontal,this->centralWidget());
m_Tree.setParent(sp);
m_Canvas.setParent(sp);
sp->setStretchFactor(1,10);
QHBoxLayout* hclay = new QHBoxLayout(this->centralWidget());
hclay->addWidget(sp);
connect(&m_Tree,SIGNAL( doubleClicked( QModelIndex )),this, SLOT(openStyleDlg(QModelIndex)));
qDebug()<<885544;
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::showMap()
{
//1.初始化
//设置插件及资源目录前缀
QDir dir(qApp->applicationDirPath());//获取应用程序所在路径
QString strAppPath(dir.absolutePath());
QgsProviderRegistry::instance( strAppPath + "/QGIS_Plugins");//注册插件
qDebug()<<"插件目录为" + strAppPath + "/QGIS_Plugins";
//设置资源目录
QgsApplication::setPkgDataPath(strAppPath);
//设置GDAL_DATA
QString strENVValue = strAppPath + "/resources/gdal_data";
if (!qputenv( "GDAL_DATA", strENVValue.toStdString().c_str() ))
{
std::cout << "GDAL_DATA设置失败" << std::endl;
}
//2读取工程
QFileInfo pro("F:/VBF/Data/QGIS/shp/bac/VBF_CommonMapbac.qgs");
QgsProject* pPro = QgsProject::instance();
if((!pPro) || (!pPro->read(pro)))//读取工程失败
{
std::cout << "读取工程失败" << std::endl;
return ;
}
std::cout<<"GDAL_DATA设置失败\n";
QgsLayerTreeModel* model = new QgsLayerTreeModel( QgsProject::instance()->layerTreeRoot(), this );
model->setFlag( QgsLayerTreeModel::AllowNodeReorder );
model->setFlag( QgsLayerTreeModel::AllowNodeRename );
model->setFlag( QgsLayerTreeModel::AllowNodeChangeVisibility );
model->setFlag( QgsLayerTreeModel::ShowLegendAsTree );
model->setFlag( QgsLayerTreeModel::UseEmbeddedWidgets );
m_Tree.setModel( model );
m_Tree.collapseAll();
connect(&m_Canvas,SIGNAL(extentsChanged()),this, SLOT(extentChanged()));
//设置图层
QList <QgsMapCanvasLayer> listCanvasLayer;
QList<QgsLayerTreeLayer*> listLayer = QgsProject::instance()->layerTreeRoot()->findLayers();
foreach (QgsLayerTreeLayer* pLayer, listLayer)
{
QgsMapCanvasLayer CanvasLayer(pLayer->layer());
listCanvasLayer.append(CanvasLayer);
}
QgsMapToolPan* pTool = new QgsMapToolPan(&m_Canvas);
m_Canvas.setMapTool(pTool);
m_Canvas.setLayerSet(listCanvasLayer);
m_Canvas.zoomToFullExtent();
m_bridge = new QgsLayerTreeMapCanvasBridge(QgsProject::instance()->layerTreeRoot(), &m_Canvas, this);
m_Canvas.setParallelRenderingEnabled(true);
}
void MainWindow::extentChanged()
{
m_Tree.layerTreeModel()->setLegendMapViewData( m_Canvas.mapUnitsPerPixel(), m_Canvas.mapSettings().outputDpi(), m_Canvas.scale());
}
void MainWindow::openStyleDlg(QModelIndex index)
{
if (QgsSymbolV2LegendNode* node = dynamic_cast<QgsSymbolV2LegendNode*>( m_Tree.currentLegendNode() ))//图例节点
{
//获取符号
const QgsSymbolV2* originalSymbol = node->symbol();
if ( !originalSymbol ) return;
QScopedPointer< QgsSymbolV2 > symbol( originalSymbol->clone() );
QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer*>( node->layerNode()->layer() );
QgsSymbolV2SelectorDialog dlg( symbol.data(), QgsStyleV2::defaultStyle(), vlayer, this );
dlg.setMapCanvas( &m_Canvas );
if ( dlg.exec() )
{
node->setSymbol( symbol.take() );
}
return;
}
if(QgsVectorLayer* vlayer = dynamic_cast<QgsVectorLayer*>( m_Tree.currentLayer() ))//图层节点
{
if (!vlayer->rendererV2()) return;
// try{
// QgsSingleSymbolRendererV2* pRender = QgsSingleSymbolRendererV2::convertFromRenderer(vlayer->rendererV2());
// }
// catch(...){
// qDebug()<<555;
// }
//return;
// QgsSingleSymbolRendererV2* pRender = QgsSingleSymbolRendererV2::convertFromRenderer(vlayer->rendererV2());
QgsSingleSymbolRendererV2* pRender = NULL;
try {
pRender = dynamic_cast<QgsSingleSymbolRendererV2*>(vlayer->rendererV2());
}
catch(...){
qDebug()<<45789;
}
if (!pRender) return;
QScopedPointer< QgsSymbolV2 > symbol( pRender->symbol()->clone() );
QgsSymbolV2SelectorDialog dlg(symbol.data(), QgsStyleV2::defaultStyle(), vlayer, m_Tree.window() );
dlg.setMapCanvas( &m_Canvas );
if ( dlg.exec() )
{
pRender->setSymbol( symbol.take() );
vlayer->triggerRepaint();
m_Tree.refreshLayerSymbology(vlayer->id());
}
if (QgsProject::instance()->write()) qDebug() <<"保存失败";
}
}
#include "MainWindow.h"
#include
#include
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
设置文件编码
// QApplication::addLibraryPath("./plugins");
//return 0;
QTextCodec* code= QTextCodec::codecForName ( "GBK" );
QTextCodec::setCodecForCStrings(code);
QTextCodec::setCodecForTr(code);
QTextCodec::setCodecForLocale(code);
MainWindow w;
w.showMap();
w.showMaximized();
return a.exec();
}
#-------------------------------------------------
#
# Project created by QtCreator 2020-09-07T08:41:12
#
#-------------------------------------------------
QT += core gui xml
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG +=console
CONFIG +=rtti
TARGET = SymbolConfigTool
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
DEFINES += CORE_EXPORT=Q_DECL_IMPORT
DEFINES += GUI_EXPORT=Q_DECL_IMPORT
DEFINES += noexcept=
DEFINES += override=
DEFINES += nullptr=0
DEFINES += _USE_MATH_DEFINES
DEFINES -= HAVE_TOUCH
#3rdparty
INCLUDEPATH += E:\VBF_GlobalGIS\3rdParty_vs2010_x64\include
INCLUDEPATH += E:\VBF_GlobalGIS\3rdParty_vs2010_x64\include\sqlite3
#QGIS
INCLUDEPATH += ../../3rdParty/include\
../../3rdParty/include/core\
../../3rdParty/include/core/geos\
../../3rdParty/include/core/geometry\
../../3rdParty/include/core/layertree\
../../3rdParty/include/core/raster\
../../3rdParty/include/core/symbology-ng\
../../3rdParty/include/gui\
../../3rdParty/include/gui/layertree\
../../3rdParty/include/gui/symbology-ng\
../../3rdParty/include/gui/editorwidgets\
../../3rdParty/include/gui/effects\
CONFIG(debug, debug|release){
DESTDIR = $$PWD/../build/bin/Debug
TARGET = SymbolConfigToold
LIBS += -L$$PWD/../../3rdParty/lib -lqgis_cored -lqgis_guid #-lVBF_SliceByProd
}else{
DESTDIR = $$PWD/../build/bin/Release
TARGET = SymbolConfigTool
LIBS += -L$$PWD/../../3rdParty/lib -lqgis_core -lqgis_gui #-lVBF_SliceByPro
}
SOURCES += main.cpp\
MainWindow.cpp
HEADERS += \
MainWindow.h
FORMS += \
gssymbolv2selectordialogbase.ui
最后的效果
其它阅读
HCZJEarth介绍