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