QGIS中MVC架构-接口的设计

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

QGIS是基于QT开源框架的二维地理信息处理工具,使用非常方便,同样也是开源的。大家除了使用QGIS加载显示二维地图矢量或者栅格数据外,还要在二维地图上显示一些其他的基于WGS84坐标系自定义数据,比如点、线和多边形等。除了显示以外还有有相应的数鼠标操作,比如鼠标选中或者鼠标进行拖动等。

上面这些需求体现了一个程序中常见的三要素:数据、显示和操作。数据也就是模型(Model);显示(View)就是把数据通过某种方式显示出来,给用户以视觉直观的感受;控制(Control)就是对数据的控制,最直接的方式就是通过鼠标和键盘来控制。

下面看一个例子:
在这里插入图片描述
上面的这个示例实现了:
1>.时间在变化;(数据)
2>.显示时间变化;(显示)
3>.并且可以通过鼠标拖动时间显示的位置。(控制)

1.首先要定义时间,把时间显示封装到一个类中:
实现功能:
a).设置时间;
b).获取时间;
c).时间自增自减。

//时间

class RunningTime {
public:
	RunningTime();
	RunningTime(const RunningTime&rt);
	RunningTime(int y, int mn, int d, int h, int mi, int s, int mils = 0);
	~RunningTime();

	//年
	inline void setYear(int y) {
		_year = y;
	}
	inline int getYear() {
		return _year;
	}

	//月
	inline void setMonth(int m) {
		_month = m;
	}
	inline int getMonth() {
		return _month;
	}

	//日
	inline void setDay(int d) {
		_day = d;
	}
	inline int getDay() {
		return _day;
	}

	//时
	inline void setHour(int h) {
		_hour = h;
	}
	inline int getHour() {
		return _hour;
	}

	//分
	inline void setMinute(int m) {
		_minute = m;
	}
	inline int getMinute() {
		return _minute;
	}

	//秒
	inline void setSecond(int s) {
		_second = s;
	}
	inline int getSecond() {
		return _second;
	}

	//毫秒
	inline void setMilliSecond(int ms) {
		_milliSecond = ms;
	}
	inline int getMilliSecond() {
		return _milliSecond;
	}
	
	//步增
	void stepUp(int stepMilliSecond = 1000);
	//步减
	void stepDown(int stepMilliSecond = 1000);

private:
	int _year ;//年
	int _month ;//月
	int _day ;//日
	int _hour ;//时
	int _minute ;//分
	int _second ;//秒
	int _milliSecond ;//毫秒
};

RunningTime::RunningTime() {
	_year = 2018;//年
	_month = 12;//月
	_day = 25;//日
	_hour = 11;//时
	_minute = 36;//分
	_second = 0;//秒
	_milliSecond = 0;//毫秒
}

RunningTime::RunningTime(int y, int mn, int d, int h, int mi, int s, int mils) {
	_year = y;
	_month = mn;
	_day = d;
	_hour = h;
	_minute = mi;
	_second = s;
	_milliSecond = mils;
}

RunningTime::RunningTime(const RunningTime&rt) {
	_year = rt._year;
	_month = rt._month;
	_day = rt._day;
	_hour = rt._hour;
	_minute = rt._minute;
	_second = rt._second;
	_milliSecond = rt._milliSecond;
}

RunningTime::~RunningTime() {
}

void RunningTime::stepUp(int stepMilliSecond) {
	_milliSecond += stepMilliSecond;
	if (_milliSecond >= 1000) {
		_second += _milliSecond / 1000;
		_milliSecond = _milliSecond % 1000;
		if (_second >= 60) {
			_minute += _second / 60;
			_second = _second % 60;
			if (_minute >= 60) {
				_hour += _minute / 60;
				_minute = _minute % 60;
				if (_hour >= 24) {
					_day++;
					_hour = _hour % 24;
				}
			}
		}
	}
}

void RunningTime::stepDown(int stepMilliSecond ) {
	_milliSecond -= stepMilliSecond;
	if (_milliSecond <= 0) {
		_second--;
		_milliSecond = 0;
		if (_second < 0) {
			_minute--;
			_second = 59;
			if (_minute < 0) {
				_hour--;
				_minute = 59;
				if (_hour < 0) {
					_hour = 23;
					_day--;
				}
			}
		}
	}
}

2.定义显示的接口基类:

//绘制接口
class QPainter;

class IDisplay {
public:

	//设置地图范围
	virtual void setMapRange(int w, int h);
	//设置比例
	virtual void setScale(double s);

	//初始化显示
	virtual void initDisplay();

	//整体绘制
	virtual void draw(QPainter* p);

};
void IDisplay::setMapRange(int w, int h) {

}

void IDisplay::setScale(double s) {

}

void IDisplay::initDisplay() {

}

void IDisplay::draw(QPainter* p) {

}

3.定义一个对所有显示的管理类:
实现功能:
a).添加绘制;
b).绘制内容;
c).显示绘制的图片。

#define DisplayMgr() (DisplayManager::getInstacne())

class  DisplayManager {
private:
	DisplayManager();
	static DisplayManager* instance;
public:
	static DisplayManager* getInstacne();
	//添加绘制对象
	void addRender(IDisplay* renderObj);

	//初始化大小
	void init(QSize size);

	//重新定义大小
	void resize(QSize size);

	//设置比例
	void setScale(double s);

	//绘制初始化
	void initDraw();

	//绘制内容
	void draw();

	//显示绘制
	void show(QPainter* painter);

private:
	QPixmap* _displayPixmap = nullptr;//绘制图片
	std::vector<IDisplay*> _displayObjs;
};
DisplayManager* DisplayManager::instance = new DisplayManager;

DisplayManager::DisplayManager() {
	_displayObjs.clear();
}

DisplayManager* DisplayManager::getInstacne() {
	return instance;
}

void DisplayManager::addRender(IDisplay* renderObj) {
	_displayObjs.push_back(renderObj);
}

void DisplayManager::init(QSize size) {
	_displayPixmap = new QPixmap(size);
	_displayPixmap->fill(Qt::transparent);

	std::vector<IDisplay*>::iterator it;
	for (it = _displayObjs.begin(); it != _displayObjs.end(); it++) {
		(*it)->setMapRange(size.width(), size.height());
	}
}

void DisplayManager::resize(QSize size) {
	QPixmap* newPix = new QPixmap(size);
	newPix->fill(Qt::transparent);

	delete _displayPixmap;
	_displayPixmap = newPix;

	std::vector<IDisplay*>::iterator it;
	for (it = _displayObjs.begin(); it != _displayObjs.end(); it++) {
		(*it)->setMapRange(size.width(), size.height());
	}
}

void DisplayManager::setScale(double s) {
	std::vector<IDisplay*>::iterator it;
	for (it = _displayObjs.begin(); it != _displayObjs.end(); it++) {
		(*it)->setScale(s);
	}
}

void DisplayManager::initDraw() {
	if (_displayPixmap != nullptr) {
		_displayPixmap->fill(Qt::transparent);
	}

	std::vector<IDisplay*>::iterator it;
	for (it = _displayObjs.begin(); it != _displayObjs.end(); it++) {
		(*it)->initDisplay();
	}
}

void DisplayManager::draw() {
	QPainter p(_displayPixmap);
	p.setRenderHints(QPainter::Antialiasing | QPainter::HighQualityAntialiasing, true);
	p.setOpacity(1.0f);

	std::vector<IDisplay*>::iterator it;
	for (it = _displayObjs.begin(); it != _displayObjs.end(); it++) {
		(*it)->draw(&p);
	}
}

void DisplayManager::show(QPainter* painter) {
	painter->drawPixmap(0, 0, *_displayPixmap);
}

4.定义鼠标操作的接口基类:

class IMouseEvent {
public:
	IMouseEvent();
	~IMouseEvent();

	virtual void mouseDoubleClick(QMouseEvent * event);
	virtual void mouseRelease(QMouseEvent *event);
	virtual void mouseMove(QMouseEvent * event);
	virtual void mousePress(QMouseEvent * event);
	virtual void wheel(QWheelEvent * event);

	//设置当前鼠标事件是否可用
	void setEventUse(bool b) {
		_mouseEventUse = b;
	}

	const bool getEventUse() {
		return _mouseEventUse;
	}

protected:
	bool _mouseEventUse = true;//设置当前平台鼠标事件可用
};
IMouseEvent::IMouseEvent() {
}


IMouseEvent::~IMouseEvent() {
}

void IMouseEvent::mouseDoubleClick(QMouseEvent * event) {

}

void IMouseEvent::mouseRelease(QMouseEvent *event) {

}

void IMouseEvent::mouseMove(QMouseEvent * event) {

}

void IMouseEvent::mousePress(QMouseEvent * event) {

}

void IMouseEvent::wheel(QWheelEvent * event) {

}

5.定时鼠标操作的管理类:

#define MouseMgr() (MouseEventManager::getInstance())

class MouseEventManager {
private:
	MouseEventManager();
	static MouseEventManager* _instance;
public:
	~MouseEventManager();
	static MouseEventManager* getInstance();

public:
	virtual void mouseDoubleClick(QMouseEvent * event);
	virtual void mouseRelease(QMouseEvent *event);
	virtual void mouseMove(QMouseEvent * event);
	virtual void mousePress(QMouseEvent * event);
	virtual void wheel(QWheelEvent * event);

	virtual void addMouseEvent(IMouseEvent* map);
	virtual void removeMouseEvent(IMouseEvent* map);

protected:
	std::vector<IMouseEvent*> _objList;//对象列表
};

MouseEventManager* MouseEventManager::_instance = new MouseEventManager;

MouseEventManager::MouseEventManager() {
}

MouseEventManager::~MouseEventManager() {
}

MouseEventManager* MouseEventManager::getInstance() {
	return _instance;
}

void MouseEventManager::mouseDoubleClick(QMouseEvent * event) {
	std::vector<IMouseEvent*>::iterator it;
	for (it = _objList.begin(); it != _objList.end(); it++) {
		if ((*it)->getEventUse()) {
			(*it)->mouseDoubleClick(event);
		}
	}
}

void MouseEventManager::mouseRelease(QMouseEvent *event) {
	std::vector<IMouseEvent*>::iterator it;
	for (it = _objList.begin(); it != _objList.end(); it++) {
		if ((*it)->getEventUse()) {
			(*it)->mouseRelease(event);
		}
	}
}

void MouseEventManager::mouseMove(QMouseEvent * event) {
	std::vector<IMouseEvent*>::iterator it;
	for (it = _objList.begin(); it != _objList.end(); it++) {
		if ((*it)->getEventUse()) {
			(*it)->mouseMove(event);
		}
	}
}

void MouseEventManager::mousePress(QMouseEvent * event) {
	std::vector<IMouseEvent*>::iterator it;
	for (it = _objList.begin(); it != _objList.end(); it++) {
		if ((*it)->getEventUse()) {
			(*it)->mousePress(event);
		}
	}
}

void MouseEventManager::wheel(QWheelEvent * event) {
	std::vector<IMouseEvent*>::iterator it;
	for (it = _objList.begin(); it != _objList.end(); it++) {
		if ((*it)->getEventUse()) {
			(*it)->wheel(event);
		}
	}
}

void MouseEventManager::addMouseEvent(IMouseEvent* map) {
	_objList.push_back(map);
}

void MouseEventManager::removeMouseEvent(IMouseEvent* map) {
	std::vector<IMouseEvent*>::iterator it;
	for (it = _objList.begin(); it != _objList.end(); it++) {
		if ((*it) == map) {
			_objList.erase(it);
			return;
		}
	}
}

6.定义时间同步接口
功能:可以定义时间同步接口,通过外部来传入时间控制;也可以显示时间类的自身定义定时器实现时间控制。

class IRunPlayTime {
public:
	IRunPlayTime();
	~IRunPlayTime();

	virtual void playTime(void* pt);
};

7.时间显示类:定义显示内容,包括显示的矩形背景色、显示字体等内容。

这个时间显示类同时具有:时间变化、显示和鼠标操作功能,所有需要同时继承以上三个接口 IDisplay 、IMouseEvent、IRunPlayTime。

class ReplayTimeShow :public IDisplay
	, public IMouseEvent
	, public IRunPlayTime {
public:
	ReplayTimeShow();
	~ReplayTimeShow();

	virtual void draw(QPainter* p)override;

	virtual void mousePress(QMouseEvent * event)override;
	virtual void mouseRelease(QMouseEvent *event)override;
	virtual void mouseMove(QMouseEvent * event)override;

	void playTime(void* pt)override;

private:
	QPen _pen;
	QFont _font;
	int _stepMillS;//间隔时间
	
	QRect _rectText;

	bool _bLBDown = false;//鼠标左键按下
	int _mLDownX, _mLDownY;//鼠标左键按下时位置
	int _ptLeftTopX;//左上角的坐标X
	int _ptLeftTopY;//左上角的坐标Y

	const int _W = 110;
	const int _H = 65;

	RunningTime* _currentTime = nullptr;//当前时间
};

ReplayTimeShow::ReplayTimeShow() {
	_pen.setStyle(Qt::SolidLine);
	_pen.setWidth(0);
	_pen.setColor(QColor(0, 0, 0)/*QColor(222, 155, 67)*/);

	_font.setFamily(QStringLiteral("微软雅黑"));
	_font.setPointSize(10);
	_font.setBold(true);

	_stepMillS = 0;

	_mLDownX = 0;
	_mLDownY = 0;

	_ptLeftTopX = 10;
	_ptLeftTopY = 30;
	_rectText.setLeft(_ptLeftTopX);
	_rectText.setTop(_ptLeftTopY);

	_rectText.setRight(_ptLeftTopX + _W);
	_rectText.setBottom(_ptLeftTopY + _H);

	_currentTime = new RunningTime;

	RPTMgr()->addPlayTime(this);
}

ReplayTimeShow::~ReplayTimeShow() {
}

void ReplayTimeShow::draw(QPainter* p) {
	p->setPen(_pen);
	p->setFont(_font);

	QString strTime;

	strTime += QString("%0").arg(_currentTime->getHour(), 2, 10, QChar('0'));
	strTime += QStringLiteral(":");
	strTime += QString("%0").arg(_currentTime->getMinute(), 2, 10, QChar('0'));
	strTime += QStringLiteral(":");
	strTime += QString("%0").arg(_currentTime->getSecond(), 2, 10, QChar('0'));

	strTime += "\n ";
	strTime += QString("%0").arg(_currentTime->getYear(), 2, 10, QChar('0'));
	strTime += QStringLiteral("年");
	strTime += QString("%0").arg(_currentTime->getMonth(), 2, 10, QChar('0'));
	strTime += QStringLiteral("月");
	strTime += QString("%0").arg(_currentTime->getDay(), 2, 10, QChar('0'));
	strTime += QStringLiteral("日");

	p->setBrush(QColor(0, 0, 255, 80));
	p->drawRect(_rectText);
	p->drawText(_rectText, Qt::AlignVCenter | Qt::AlignLeft, strTime);
}

void ReplayTimeShow::mousePress(QMouseEvent * event) {
	QPoint pt = event->pos();
	switch (event->button()) {
	case Qt::LeftButton:
		if (_rectText.contains(pt)) {
			_bLBDown = true;
			_mLDownX = pt.x();
			_mLDownY = pt.y();
		}

		break;
	}

}

void ReplayTimeShow::mouseRelease(QMouseEvent *event) {
	_bLBDown = false;
}

void ReplayTimeShow::mouseMove(QMouseEvent * event) {
	if (_bLBDown) {
		QPoint pt = event->pos();
		int disX = _mLDownX - pt.x();
		int disY = _mLDownY - pt.y();
		_mLDownX = pt.x();
		_mLDownY = pt.y();

		_ptLeftTopX -= disX;
		_ptLeftTopY -= disY;
		_rectText.setLeft(_ptLeftTopX);
		_rectText.setTop(_ptLeftTopY);
		_rectText.setRight(_ptLeftTopX + _W);
		_rectText.setBottom(_ptLeftTopY + _H);
		GlobalUseInst()->load2DMapCanvas()->update();
	}
}

void ReplayTimeShow::playTime(void* pt) {
	_currentTime = (RunningTime*)pt;
}

8.以上就是使用到的主要的类,下面就是要把整个MVC框架搭建起来。

QGIS中地图的显示都是在类QgsMapCanvas中,所有我们继承这个类然后重新其中的一些方法:

class Map2DCanvas : public QgsMapCanvas {
	Q_OBJECT

public:
	Map2DCanvas(QWidget* parent = nullptr, const char*name = nullptr);
	~Map2DCanvas();

private:
	void init();
	void paintEvent(QPaintEvent *event) override;
	void mouseDoubleClickEvent(QMouseEvent * event) override;
	void mousePressEvent(QMouseEvent * event) override;
	void mouseReleaseEvent(QMouseEvent *event)override;
	void mouseMoveEvent(QMouseEvent * event) override;
	void wheelEvent(QWheelEvent * event) override;
	void closeEvent(QCloseEvent *event);
	void resizeEvent(QResizeEvent *event)override;
private:
}
Map2DCanvas::Map2DCanvas(QWidget* parent , const char*name )
	: QgsMapCanvas(parent, name) {
	init();
}

Map2DCanvas::~Map2DCanvas() {
}

void Map2DCanvas::init() {
	DisplayMgr()->init(size());
}

void Map2DCanvas::paintEvent(QPaintEvent *event) {
	QgsMapCanvas::paintEvent(event);
	QPainter painter(viewport());
	DisplayMgr()->setScale(scale());
}

void Map2DCanvas::mouseDoubleClickEvent(QMouseEvent * event) {
	QgsMapCanvas::mouseDoubleClickEvent(event);
	MouseMgr()->mouseDoubleClick(event);
}

void Map2DCanvas::mousePressEvent(QMouseEvent * event) {
	QgsMapCanvas::mousePressEvent(event);
	MouseMgr()->mousePress(event);
}

void Map2DCanvas::mouseReleaseEvent(QMouseEvent *event) {
	QgsMapCanvas::mouseReleaseEvent(event);
	MouseMgr()->mouseRelease(event);
}

void Map2DCanvas::mouseMoveEvent(QMouseEvent * event) {
	QgsMapCanvas::mouseMoveEvent(event);
	MouseMgr()->mouseMove(event);
}

void Map2DCanvas::wheelEvent(QWheelEvent * event) {
	QgsMapCanvas::wheelEvent(event);
	MouseMgr()->wheel(event);
}

void Map2DCanvas::closeEvent(QCloseEvent *event) {

}

void Map2DCanvas::resizeEvent(QResizeEvent *event) {
	QgsMapCanvas::resizeEvent(event);
	DisplayMgr()->resize(size());
}

9.开始调用:

//时间展示
	ReplayTimeShow* timeShow = new ReplayTimeShow;
	DisplayMgr()->addRender(timeShow);
	MouseMgr()->addMouseEvent(timeShow);

以上就可以完成了!

aaa

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

wb175208

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

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

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

打赏作者

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

抵扣说明:

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

余额充值