近期工作中用到回调函数,回调函数是C语言中的概念,在C++中使用回调函数回破坏类及其对象的封装性。但是有的时候也要使用一下,那怎么办呢?
也就是把需要回调的函数定义成静态函数的形式调用:(QT5.7)
设计到两个类:
GeoTree:自定义的树形控件,主要用来显示图像要素
GeoManager:主要用来管理图形要素的,包括添加、删除、修改绘制等。
以下只是列出了部分代码,并没有贴出全部代码,主要是为了演示,如何回调类中的函数。采用的主要思想就是调用另外一个类的静态函数,并且传递类对象指针的形式实现。仅供参考。
GeoTree.h
class GeoTree : public QTreeWidget {
Q_OBJECT
public:
GeoTree(QWidget *parent);
~GeoTree();
static void callbackNewGeo(GeoTree*treeWidget,GEO_TYPE type);
private:
void init();
void initTree();
public:
QTreeWidgetItem* pointRootItem; //点
QTreeWidgetItem* lineRootItem; //线
QTreeWidgetItem* polygonRootItem; //多边形
QTreeWidgetItem* rectRootItem; //矩形
QTreeWidgetItem* circleRootItem; //圆
};
GeoTree.cpp
#include "stdafx.h"
#include "GeoTree.h"
#include "GeoDrawDef.h"
#include "GeoManager.h"
GeoTree::GeoTree(QWidget *parent)
: QTreeWidget(parent) {
init();
}
GeoTree::~GeoTree() {
}
//初始化
void GeoTree::init() {
this->setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotRClick(QPoint)));
connect(this, SIGNAL(itemPressed(QTreeWidgetItem*, int)), this, SLOT(slotPressItem(QTreeWidgetItem*)));
initTree();
theGeoType = GEO_TYPE_NULL;
GeoManager::getInstance()->setInvokeNewGeo(this, GeoTree::callbackNewGeo);
}
//初始换树形控件
void GeoTree::initTree() {
pointRootItem = new QTreeWidgetItem(this, QStringList(gGeoDrawType[0]));
pointRootItem->setData(0, Qt::UserRole, QVariant(GEO_TYPE_POINT));
this->addTopLevelItem(pointRootItem);
lineRootItem = new QTreeWidgetItem(this, QStringList(gGeoDrawType[1]));
lineRootItem->setData(0, Qt::UserRole, QVariant(GEO_TYPE_LINE));
this->addTopLevelItem(lineRootItem);
polygonRootItem = new QTreeWidgetItem(this, QStringList(gGeoDrawType[2]));
polygonRootItem->setData(0, Qt::UserRole, QVariant(GEO_TYPE_POLYGON));
this->addTopLevelItem(polygonRootItem);
rectRootItem = new QTreeWidgetItem(this, QStringList(gGeoDrawType[3]));
rectRootItem->setData(0, Qt::UserRole, QVariant(GEO_TYPE_RECT));
this->addTopLevelItem(rectRootItem);
circleRootItem = new QTreeWidgetItem(this, QStringList(gGeoDrawType[4]));
circleRootItem->setData(0, Qt::UserRole, QVariant(GEO_TYPE_CIRCLE));
this->addTopLevelItem(circleRootItem);
}
//静态回调函数-新建图形的时候调用
void GeoTree::callbackNewGeo(GeoTree*treeWidget, GEO_TYPE type) {
switch (type) {
case GEO_TYPE_NULL:
break;
case GEO_TYPE_POINT:{
QString name = GeoManager::getInstance()->getCurrentPoint()->name;
QTreeWidgetItem* pointItem = new QTreeWidgetItem(treeWidget->pointRootItem, QStringList(name));
treeWidget->pointRootItem->setExpanded(true);
break;
}
case GEO_TYPE_LINE:{
QString name = GeoManager::getInstance()->getCurrentLine()->name;
QTreeWidgetItem* lineItem = new QTreeWidgetItem(treeWidget->lineRootItem, QStringList(name));
treeWidget->lineRootItem->setExpanded(true);
break;
}
case GEO_TYPE_POLYGON:{
QString name = GeoManager::getInstance()->getCurrentPolygon()->name;
QTreeWidgetItem* polygonItem = new QTreeWidgetItem(treeWidget->polygonRootItem, QStringList(name));
treeWidget->polygonRootItem->setExpanded(true);
break;
}
case GEO_TYPE_RECT:{
QString name = GeoManager::getInstance()->getCurrentRect()->name;
QTreeWidgetItem* rectItem = new QTreeWidgetItem(treeWidget->rectRootItem, QStringList(name));
treeWidget->rectRootItem->setExpanded(true);
break;
}
case GEO_TYPE_CIRCLE:{
QString name = GeoManager::getInstance()->getCurrentCircle()->name;
QTreeWidgetItem* circleItem = new QTreeWidgetItem(treeWidget->circleRootItem, QStringList(name));
treeWidget->circleRootItem->setExpanded(true);
break;
}
default:
break;
}
}
GeoManager.h
#pragma once
#include "GeoDrawDef.h"
#include <vector>
using namespace std;
class QPaintEvent;
class GeoTree;
//声明回调函数
typedef void(*pNewGeo)(GeoTree* tree, GEO_TYPE type);
class GeoManager {
protected:
GeoManager();
public:
~GeoManager();
public:
static GeoManager* getInstance();//获取单例
void addGeo(GeoPoint* geoPt);
void addGeo(GeoLine* geoLine);
void addGeo(GeoPolygon* geoPolygon);
void addGeo(GeoRect* geoRect);
void addGeo(GeoCircle* geoCircle);
void setInvokeNewGeo(GeoTree* tree, pNewGeo newGeo);
private:
static GeoManager* instance;
pNewGeo addNewGeo;
GeoTree* treeWidget;
};
GeoManager.cpp
#include "stdafx.h"
#include "GeoManager.h"
#include "CoordManager.h"
#include "Map\MyMap.h"
#include <QVector.h>
GeoManager* GeoManager::instance = new GeoManager;
GeoManager::GeoManager() {
}
GeoManager::~GeoManager() {
}
GeoManager* GeoManager::getInstance() {
return instance;
}
//添加点要素
void GeoManager::addGeo(GeoPoint* geoPt) {
pointList.push_back(geoPt);
currentPoint = pointList.size() - 1;
addNewGeo(treeWidget, currentGeoType);
}
//添加线
void GeoManager::addGeo(GeoLine* geoLine) {
lineList.push_back(geoLine);
currentLine = lineList.size() - 1;
addNewGeo(treeWidget, currentGeoType);
}
//添加多边形要素
void GeoManager::addGeo(GeoPolygon* geoPolygon) {
polygonList.push_back(geoPolygon);
currentPolygon = polygonList.size() - 1;
addNewGeo(treeWidget, currentGeoType);
}
//添加矩形要素
void GeoManager::addGeo(GeoRect* geoRect) {
rectList.push_back(geoRect);
currentRect = rectList.size() - 1;
addNewGeo(treeWidget, currentGeoType);
}
//添加圆元素
void GeoManager::addGeo(GeoCircle* geoCircle) {
circleList.push_back(geoCircle);
currentCircle = circleList.size() - 1;
addNewGeo(treeWidget, currentGeoType);
}
//添加圆心点
void GeoManager::addCircleCenter(double lon, double lat, double alt) {
circleList[currentCircle]->centerLon = lon;
circleList[currentCircle]->centerLat = lat;
circleList[currentCircle]->centerAlt = alt;
}
//设置回调函数
void GeoManager::setInvokeNewGeo(GeoTree* tree, pNewGeo newGeo) {
treeWidget = tree;
addNewGeo = newGeo;
}
下图就展示了,当我创建一个图像元素的时候,在左侧的树形控件中就会显示出对应的节点来。当然还用多种方法实现,本文采用的回调函数的方式实现。