C++ 设计模式之外观模式

137 篇文章 45 订阅
73 篇文章 4 订阅

在做QGIS方面的工作时,经常会用到在地图上绘制方面的需求,比如测量面积、测量长度、计算角度等等。

在绘制的时候,都会调用:paintEvent 这个函数

void MainCanvas::paintEvent(QPaintEvent *event) {
	QgsMapCanvas::paintEvent(event);
	//绘制内容
	...
}

仔细想想,如果把所有的绘制工作都放到这个函数当中,可见是一个多么庞大的函数,就是拆分成小的函数候,也会造成这个类的臃肿。稍微做一下逻辑上的修改就有可能就会引起其他方面的问题,对以后的维护造成很大的困难。

所以要把所有的绘制工作拆分成不同的小的类便于维护和修改。提供统一的外观接口

绘制面积类:

class MeasureArea : public QObject {
	Q_OBJECT

public:
	MeasureArea();
	MeasureArea(QObject *parent);
	~MeasureArea();

	//首先调用
	void initCanvas(QgsMapCanvas* c);

	void setDraw(bool b, QWidget* parent = nullptr);

	void paintEvent();
	void mousePressEvent(QMouseEvent* event);
	void mouseReleaseEvent(QMouseEvent* event);
	void mouseMoveEvent(QMouseEvent* event);
}

绘制长度类:

class TRUESYSDLL_EXPORT MeasureLine {
public:
	MeasureLine();
	~MeasureLine();

	//首先调用
	void initCanvas(QgsMapCanvas* c);

	void setDraw(bool b, QWidget* parent = nullptr);

	void paintEvent();
	void mousePressEvent(QMouseEvent* event);
	void mouseReleaseEvent(QMouseEvent* event);
	void mouseMoveEvent(QMouseEvent* event);
}

绘制角度类:

class TRUESYSDLL_EXPORT MeasureAngle {
public:
	MeasureAngle();
	~MeasureAngle();

	//首先调用
	void initCanvas(QgsMapCanvas* c);

	void setDraw(bool b);

	void paintEvent();
	void mousePressEvent(QMouseEvent* event);
	void mouseReleaseEvent(QMouseEvent* event);
	void mouseMoveEvent(QMouseEvent* event);
}

然后编写一个管理所有绘制相关的类:

class DrawManager {
private:
	DrawManager();
	static DrawManager* instance;
public:
	~DrawManager();
	static DrawManager* getInstance();
public:
	void init(QgsMapCanvas* c);
	void paintEvent(QPaintEvent *event);
	void mouseDoubleClickEvent(QMouseEvent * event);
	void mousePressEvent(QMouseEvent * event);
	void mouseReleaseEvent(QMouseEvent *event);
	void mouseMoveEvent(QMouseEvent * event);
public:
	void setMeasureLine(bool b);//设置测量线长度
	void setMeasureArea(bool b);//设置测量面积
	void setMeasureAngle(bool b);//设置测量角度
private:
	void clearDraw();
private:
	QgsMapCanvas* canvas;

	MeasureLine* measureLine;//长度测量
	MeasureArea* measureArea;//面积测量
	MeasureAngle* measureAngle;//角度测量
};

看看这个类是如何管理所有绘制工作的

void DrawManager::init(QgsMapCanvas* c) {
	canvas = c;
	CoordinateManager::getInstance()->init(canvas);
	measureLine->initCanvas(canvas);
	measureArea->initCanvas(canvas);
	measureAngle->initCanvas(canvas);
}

void DrawManager::paintEvent(QPaintEvent *event) {
	measureLine->paintEvent();
	measureArea->paintEvent();
	measureAngle->paintEvent();
}

void DrawManager::mouseDoubleClickEvent(QMouseEvent * event) {
	
}

void DrawManager::mousePressEvent(QMouseEvent * event) {
	measureLine->mousePressEvent(event);
	measureArea->mousePressEvent(event);
	measureAngle->mousePressEvent(event);
}

void DrawManager::mouseReleaseEvent(QMouseEvent *event) {
	measureLine->mouseReleaseEvent(event);
	measureArea->mouseReleaseEvent(event);
	measureAngle->mouseReleaseEvent(event);
}

void DrawManager::mouseMoveEvent(QMouseEvent * event) {
	measureLine->mouseMoveEvent(event);
	measureArea->mouseMoveEvent(event);
	measureAngle->mouseMoveEvent(event);
}

看到了吗?所有的绘制工作都在这个类中完成,包括和鼠标的操作。而且通关开关开控制当前地图上应该绘制那些那些内容:

	void setMeasureLine(bool b);//设置测量线长度
	void setMeasureArea(bool b);//设置测量面积
	void setMeasureAngle(bool b);//设置测量角度

如何调用,这主绘制类中:

void MainCanvas::init() {
	DrawManager::getInstance()->init(this);
}

void MainCanvas::paintEvent(QPaintEvent *event) {
	QgsMapCanvas::paintEvent(event);
	DrawManager::getInstance()->paintEvent(event);
}

void MainCanvas::mouseDoubleClickEvent(QMouseEvent * event) {
	DrawManager::getInstance()->mouseDoubleClickEvent(event);
}

void MainCanvas::mousePressEvent(QMouseEvent * event) {
	QgsMapCanvas::mousePressEvent(event);
	DrawManager::getInstance()->mousePressEvent(event);
}

void MainCanvas::mouseReleaseEvent(QMouseEvent *event) {
	QgsMapCanvas::mouseReleaseEvent(event);
	DrawManager::getInstance()->mouseReleaseEvent(event);
}

void MainCanvas::mouseMoveEvent(QMouseEvent * event) {
	QgsMapCanvas::mouseMoveEvent(event);
	DrawManager::getInstance()->mouseMoveEvent(event);
}

只要是在主绘制界面调用绘制相应的接口就可以了。
这样设计的好处:客户端在调用的时候,不必考虑每个绘制的过程是如何实现的,只要知道调用那个函数就可以了,而且一旦被调用就可以实现所有的绘制过程,不必单独的调用每个绘制过程,是高内聚。

这样设计的目的:使真正绘制的对象远离实际绘制的对象,实现对象与对象之间的解耦。符合C++设计中的“开闭原则”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

wb175208

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

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

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

打赏作者

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

抵扣说明:

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

余额充值