QT5.12.6+QGIS3.10二次开发(Qtcreater)(三)右键菜单、标注显示及图层样式

一、前言

本篇文章是QGIS3.10二次开发的第三个文档,可在本人首页查看所有QGIS3.10二次开发相关的文档,文档不定期更新。
https://blog.csdn.net/qfl_sdu?type=blog
本篇文章计划实现以下功能:

  1. 图层控制器右键菜单
  2. 通过右键菜单控制图层标签(label)的显示及显示的内容
  3. 通过右键菜单控制点图层的渲染效果
  4. 通过右键菜单控制线图层的渲染效果
  5. 通过右键菜单控制多边形图层的渲染效果
    这一节的内容较多,因个人工作原因,内容会逐步补充完整,前面2个功能已经实现,后面3个功能会逐渐补充上来。
    按照惯例,先上效果图:(效果图中添加了一个点图层,一个面图层,只截取了点图层的示例,面图层的操作相同就不再截图了)
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

二、图层控制器右键菜单

在上一篇文章中已经添加了图层控制器,此处说明在其基础上增加右键菜单。
(上篇链接:https://blog.csdn.net/qfl_sdu/article/details/113184043)
在QGis中,图层控制器右键菜单有个专门的抽象类QgsLayerTreeViewMenuProvider,通过继承这个类并实现 createContextMenu()这个方法,即可添加右键菜单。
在工程中添加一个类文件MyGistreeviewMenu.h和MyGistreeviewMenu.cpp,并继承QgsLayerTreeViewMenuProvider类,代码如下:
MyGistreeviewMenu.h代码:

#ifndef MYGISTREEVIEWMENU_H
#define MYGISTREEVIEWMENU_H
#include <QObject>
#include "qgslayertreeview.h"
#include "qgsmaplayer.h"
class QAction;
class QgsMapCanvas;
class MyGistreeviewMenu : public QObject, public QgsLayerTreeViewMenuProvider
{
    Q_OBJECT
public:
    MyGistreeviewMenu(QgsLayerTreeView* view,QgsMapCanvas* canvas);
    ~MyGistreeviewMenu() override;
    QMenu * createContextMenu() override; // 创建菜单
private:
    QgsLayerTreeView* m_layerTreeView;
    QgsMapCanvas* m_mapCanvas;
};

#endif // MYGISTREEVIEWMENU_H

MyGistreeviewMenu.cpp代码:

#include "mygistreeviewmenu.h"
#include "mainwindow.h"
#include <QMenu>
#include <QModelIndex>
#include <QIcon>
#include <qgswkbtypes.h>

//QGIS include
#include "qgslayertreeviewdefaultactions.h"
#include "qgslayertreenode.h"
#include "qgslayertreemodel.h"
#include "qgslayertree.h"
#include "qgsrasterlayer.h"
#include "qgsvectorlayer.h"

MyGistreeviewMenu::MyGistreeviewMenu(QgsLayerTreeView* view,QgsMapCanvas* canvas)
{
    m_layerTreeView = view;
    m_mapCanvas = canvas;
}

MyGistreeviewMenu::~MyGistreeviewMenu()
{
}
//创建菜单
QMenu *MyGistreeviewMenu::createContextMenu()
{
    QMenu* menu = new QMenu;
    QgsLayerTreeViewDefaultActions* actions = m_layerTreeView->defaultActions();
    QModelIndex idx = m_layerTreeView->currentIndex();

    // global menu
    if(!idx.isValid())
    {
        menu->addAction(actions->actionAddGroup(menu));
        menu->addAction(tr("&Expand All"),m_layerTreeView,SLOT(expandAll()));
        menu->addAction(tr("&Collapse All"),m_layerTreeView,SLOT(collapseAll()));
    }else
    {
        QgsLayerTreeNode* node = m_layerTreeView->layerTreeModel()->index2node(idx);
        //layer or group selected
        if(QgsLayerTree::isGroup(node))
        {
            menu->addAction(actions->actionZoomToGroup(m_mapCanvas,menu));
            menu->addAction(actions->actionRemoveGroupOrLayer(menu));
            menu->addAction(actions->actionRenameGroupOrLayer());
            if(m_layerTreeView->selectedNodes(true).count() >= 2)
                menu->addAction(actions->actionGroupSelected(menu));
            menu->addAction(actions->actionAddGroup(menu));
        }else if(QgsLayerTree::isLayer(node))
        {
            QgsMapLayer* layer = QgsLayerTree::toLayer(node)->layer();
            menu->addAction(actions->actionZoomToLayer(m_mapCanvas,menu));
            menu->addAction(actions->actionRemoveGroupOrLayer(menu));
            menu->addAction(tr("&Label"),MainWindow::Intance(),SLOT(slot_labelShowAction()));

            if(layer->type() == QgsMapLayerType::VectorLayer)
            {
                //点矢量图层增加点样式设置菜单
                QgsVectorLayer* veclayer = qobject_cast<QgsVectorLayer*>(layer);
                if(veclayer->geometryType() == QgsWkbTypes::PointGeometry )
                {
                    menu->addAction(tr("PointStyle"),MainWindow::Intance(),SLOT(slot_pointstyle()));
                }else if(veclayer->geometryType() == QgsWkbTypes::PolygonGeometry)
                {
                    menu->addAction(tr("PolygonStyle"),MainWindow::Intance(),SLOT(slot_polygonstyle()));
                }
            }

        }
    }
    return menu;
}

在菜单中,添加了几个槽函数:
slot_labelShowAction()用于设置矢量图层的标签显示,会在第三节中完成;
slot_pointstyle()用于设置点图层的显示方式,会在第四节的第2小节中完成;
slot_polygonstyle()用于设置面图层的显示方式,会在第四节的第4小节中完成。
线图层的相关槽函数会在后面补充上来。
在mainwindow.cpp中添加右键菜单:
添加头文件:#include “mygistreeviewmenu.h”
添加右键菜单:

//右键菜单
    m_layerTreeView->setMenuProvider(new MyGistreeviewMenu(m_layerTreeView,m_mapcanvas));
    connect(QgsProject::instance()->layerTreeRegistryBridge(),SIGNAL(addedLayersToLayerTree(const QList<QgsMapLayer*>)),this,SLOT(slot_autoSelectAddedLayer( const QList<QgsMapLayer*>)));

槽函数slot_autoSelectAddedLayer用于处理图控制器中树结构的变化,其代码如下:

//图层控制器树结构变化
void MainWindow::slot_autoSelectAddedLayer(const QList<QgsMapLayer *> layers)
{
    if ( !layers.isEmpty() )
    {
        QgsLayerTreeLayer *nodeLayer = QgsProject::instance()->layerTreeRoot()->findLayer( layers[0]->id() );

        if ( !nodeLayer )
            return;

        QModelIndex index = m_layerTreeView->layerTreeModel()->node2index( nodeLayer );
        m_layerTreeView->setCurrentIndex( index );
    }
}

因为在MyGistreeviewMenu.cpp的方法中,用到了几个槽函数,用于响应右键菜单操作,所以在mainwindow中需要添加这几个槽函数。
mainwindow.h中添加如下:

public:
static MainWindow* Intance();   //返回主窗口实例指针
public slots:
void slot_labelShowAction();    //设置图层显示标签
void slot_pointstyle();  //点样式窗口显控
void slot_polygonstyle();//面样式窗口显控
private:
static MainWindow* m_appinstance;

mainwindow.cpp中添加实现:

MainWindow* MainWindow::m_appinstance = nullptr;
//返回实例指针
MainWindow *MainWindow::Intance()
{
    return m_appinstance;
}
//设置图层显示标签
void MainWindow::slot_labelShowAction()
{//具体实现在下面的小节中说明
}
//点样式-右键菜单
void MainWindow::slot_pointstyle()
{//具体实现在下面的小节中说明
}
//面样式窗口显控-右键菜单
void MainWindow::slot_polygonstyle()
{//具体实现在下面的小节中说明
}

至此,编译运行就可以显示图层控制器的右键菜单了。

三、标签显示设置

通过一个窗口(LabelContral类)来显示图层有哪些标签字段,用户通过界面选择需要显示的标签字段。具体实现如下 :
LabelContral.h文件:

#ifndef LABELCONTRAL_H
#define LABELCONTRAL_H

#include <QWidget>

namespace Ui {
class LabelContral;
}

class LabelContral : public QWidget
{
    Q_OBJECT

public:
    explicit LabelContral(QWidget *parent = nullptr);
    ~LabelContral();

    void SetItems(QStringList items);  //设置combox列表内容
    void SetInitInfo(bool bshow,QString name);  //设置初始显示内容
    QString GetSelectedItem();         //获取选中的项
    bool isShowLabel();                     //是否显示label

private slots:
    void on_btnOk_clicked();
    void on_btnCancle_clicked();


signals:
    void sig_labelctrlBtnClicked(int,bool,QString);

private:
    Ui::LabelContral *ui;
    bool m_bshowLabels;               //是否显示字段
    QString m_strShowName;        //显示的字段名称
};

#endif // LABELCONTRAL_H

LabelContral.cpp文件:

#include "labelcontral.h"
#include "ui_labelcontral.h"
#include <QPalette>
#include <QString>
LabelContral::LabelContral(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::LabelContral)
{
    ui->setupUi(this);
    QStringList ll;
    ll<<QString::fromLocal8Bit("显示") << QString::fromLocal8Bit("不显示");
    ui->comboBox_show->addItems(ll);
    ui->comboBox_show->setCurrentIndex(1);
    m_bshowLabels = false;
    m_strShowName = "";

    setWindowTitle(QString::fromLocal8Bit("标签设置"));

    QPalette pe = this->palette();
    pe.setColor(QPalette::Background,Qt::white);
    setPalette(pe);

}

LabelContral::~LabelContral()
{
    delete ui;
}
//设置combox列表内容
void LabelContral::SetItems(QStringList items)
{
    ui->comboBox_items->clear();
    ui->comboBox_items->addItems(items);
}
//设置初始显示内容
void LabelContral::SetInitInfo(bool bshow, QString name)
{
    if(bshow)
        ui->comboBox_show->setCurrentIndex(0);
    else
        ui->comboBox_show->setCurrentIndex(1);

    if(!name.isEmpty())
        ui->comboBox_items->setCurrentText(name);
}
//获取选中的项
QString LabelContral::GetSelectedItem()
{
    return ui->comboBox_items->currentText();
}
//是否显示label
bool LabelContral::isShowLabel()
{
    return true;
}
//OK
void LabelContral::on_btnOk_clicked()
{
    int ind = ui->comboBox_show->currentIndex();
    bool sh = false;
    if(ind == 0) sh = true;

    QString name = ui->comboBox_items->currentText();

    if(sh != m_bshowLabels || name != m_strShowName)
    {
        m_bshowLabels = sh;
        m_strShowName = name;
        emit sig_labelctrlBtnClicked(1,m_bshowLabels,m_strShowName);
    }else
        emit sig_labelctrlBtnClicked(0,m_bshowLabels,m_strShowName);  //Do nothing}
//Cancle
void LabelContral::on_btnCancle_clicked()
{
    emit sig_labelctrlBtnClicked(0,m_bshowLabels,m_strShowName);
}

在mainwindow中slot_labelShowAction()槽函数:

//设置图层显示标签
void MainWindow::slot_labelShowAction()
{
    QgsMapLayer* layer =m_layerTreeView->currentLayer();
    if(layer && layer->type() == QgsMapLayerType::VectorLayer)
    {
        QgsVectorLayer* veclayer = qobject_cast<QgsVectorLayer*>(layer);

        //查找标签显示信息
        QMap<QgsVectorLayer*,StLabelShowInfo>::iterator it =  m_mapLabelshowInfo.find(veclayer);  //标签显示信息
        StLabelShowInfo st;
        if(it != m_mapLabelshowInfo.end())
            st = it.value();
        else
        {
            st.bshow = false;
            st.name = "";
        }

        QStringList items = veclayer->fields().names();
        if(m_dlgLabelctrl == nullptr)
        {
            m_dlgLabelctrl = new LabelContral();
            connect(m_dlgLabelctrl,SIGNAL(sig_labelctrlBtnClicked(int,bool,QString)),this,SLOT(slot_labelctrlChange(int,bool,QString)));
        }
        m_dlgLabelctrl->SetItems(items);
        m_dlgLabelctrl->SetInitInfo(st.bshow,st.name);
        m_dlgLabelctrl->show();
        m_dlgLabelctrl->raise();
        m_dlgLabelctrl->activateWindow();
    }
}

其中,

struct StLabelShowInfo
    {
        bool bshow;        //是否显示标签
        QString name;    //显示的标签字段
    };
    QMap<QgsVectorLayer*,StLabelShowInfo> m_mapLabelshowInfo;  //记录每个图层上一次的标签显示信息

用户设置变更后,配置界面发送信号sig_labelctrlBtnClicked,主界面通过槽函数slot_labelctrlChange来刷新地图。

//标签显示变更
void MainWindow::slot_labelctrlChange(int id,bool bchange,QString name)
{
    if(m_dlgLabelctrl)
    {
        m_dlgLabelctrl->hide();
        delete m_dlgLabelctrl;
        m_dlgLabelctrl = 0;
    }

    if(id == 1)
    {
        QgsMapLayer* ll = m_layerTreeView->currentLayer();
        if(ll && ll->type() == QgsMapLayerType::VectorLayer )
        {
            QgsVectorLayer* vecLayer =qobject_cast<QgsVectorLayer*>(ll);

            //标签显示信息查询
            QMap<QgsVectorLayer*,StLabelShowInfo>::iterator it =  m_mapLabelshowInfo.find(vecLayer);  //标签显示信息
            StLabelShowInfo st;
            if(it != m_mapLabelshowInfo.end())
            {
                st = it.value();
                m_mapLabelshowInfo.erase(it);
            }
            st.bshow = bchange;
            st.name = name;
            m_mapLabelshowInfo.insert(vecLayer,st);


            if(bchange)
            {
                //显示标签
                QgsPalLayerSettings layerSettings;
                layerSettings.drawLabels = true;
                layerSettings.fieldName = name;
                layerSettings.isExpression = false;
                layerSettings.placement = QgsPalLayerSettings::OverPoint;
                layerSettings.yOffset = 2.50;

                QgsTextBufferSettings buffersettings;
                buffersettings.setEnabled(false);
                buffersettings.setSize(1);
                buffersettings.setColor(QColor());

                QgsTextFormat format;
                QFont font("SimSun",5,5,false);
                font.setUnderline(false);
                format.setFont(font);
                format.setBuffer(buffersettings);
                layerSettings.setFormat(format);

                QgsVectorLayerSimpleLabeling * labeling = new QgsVectorLayerSimpleLabeling (layerSettings);
                vecLayer->setLabeling(labeling);
                vecLayer->setLabelsEnabled(true);
            }
            else
            {
                vecLayer->setLabelsEnabled(false);
            }
            m_mapcanvas->refresh();
        } //vecterlayer

    }// change

}

如果没有遗漏的话,至此,就可以手动配置矢量图层的标签显示了。
(因为代码是先写好的,隔了一段时间才写的文档,如有遗漏的内容请提示我一下,我会及时补充上来,谢谢。)

四、图层渲染

1、渲染类之间的关系

矢量图层(QgsVectorLayer)通过setRenderer()函数实现图层的渲染,该成员函数如下:

/**
     * Sets renderer which will be invoked to represent this layer.
     * Ownership is transferred.
     */
    void setRenderer( QgsFeatureRenderer *r);

函数中需要传入QgsFeatureRenderer类型的实例,其有多个子类:
在这里插入图片描述

包括了2.5D渲染、热力图等等渲染方式,在本节中,我们只关注更改点的基本样式,因此只关注QgsSingleSymbolRenderer的实现,该类用于单一符号的渲染。需要注意的是,如果图层中指定了该渲染方式,则图层中的符号将都采用该渲染方式,无法指定该图层中符号的个性化渲染。
QgsSingleSymbolRenderer的构造函数如下:
QgsSingleSymbolRenderer (QgsSymbol *symbol)
需要传入QgsSymbol的一个实例,QgsSymbol包括了多个子类,如下图所示:
在这里插入图片描述

QgsFillSymbolLayer:填充符号图层
QgsGeometryGeneratorSymbolLayer:几何生成符号图层
QgsLineSymbolLayer:线符号图层
QgsMarkerSymbolLayer:标记符号图层(可狭义的理解为点的渲染)

2、点图层渲染

(1)点渲染方式
QgsEllipseSymbolLayer:椭圆形符号图层,实际上还能够支持圆,矩形,菱形,十字,箭头,半角,三角形,右三角形,左三角形,半圆形符号,可通过setShape函数设定。
QgsFontMarkerSymbolLayer:字体标识符号图层,在一些应用中,会把特殊符号做成字体,然后在程序中加载该字体,从而像使用英文字母一样使用这些符号。该类即为使用字体来渲染图层。
QgsSvgMarkerSymbolLayer:使用svg图渲染图层。(尝试用其它格式的图片看看效果)
(2)内置形状渲染
使用(1)中描述的形状进行渲染。
未完,待续…
(3)svg图渲染
未完,待续…

3、线图层渲染

未完,待续…

4、面图层渲染

未完,待续…

  • 10
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 28
    评论
QGIS是一个开源的地理信息系统软件,可以用于地制作、空间数据分析和地理空间数据可视化等。在进行QGISQt二次开发时,需要进行一些配置和修改。 首先,根据引用\[1\]和引用\[2\]中的代码,可以看到在main.cpp文件中,需要包含"QtWidgetsApplication1.h"和"qgsapplication.h"头文件,并进行一些初始化操作,如设置QGIS的安装路径和初始化QGIS应用。 然后,根据引用\[3\]中的代码,可以看到在修改后的main.cpp文件中,需要包含"mainwindow.h"和"qgsapplication.h"头文件,并进行一些初始化操作,如设置插件路径和初始化QGIS应用。 在进行QGISQt二次开发时,可以根据自己的需求进行相应的修改和扩展,例如创建自定义的窗体、添加功能模块等。可以参考QGIS的官方文档和开发者社区的资源,获取更多关于QGISQt二次开发的信息和示例代码。 总结起来,QGISQt二次开发需要进行一些配置和修改,包括包含相应的头文件、进行初始化操作等。可以根据自己的需求进行相应的修改和扩展。 #### 引用[.reference_title] - *1* *2* [VS2019+QT5.15.2+QGIS二次开发环境搭建(非源码方式)](https://blog.csdn.net/danshiming/article/details/126617074)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [QT5.12.6+QGIS3.10二次开发Qtcreater)(一)环境搭建](https://blog.csdn.net/qfl_sdu/article/details/112967169)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qfl_sdu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值