主要介绍Graphics View框架,实现地图的浏览、放大、缩小,以及显示各个位置的视图、场景和地图坐标
效果图:
mapwidget.h
#ifndef MAPWIDGET_H
#define MAPWIDGET_H
#include <QLabel>
#include <QMouseEvent>
#include <QGraphicsView>
class MapWidget : public QGraphicsView
{
public:
MapWidget();
void readMap();
QPointF mapToMap(QPointF); //实现场景坐标系与地图坐标之间的映射,以获得某点的经纬度值
public slots:
void slotZoom(int);
QPixmap map;
protected:
void drawBackground(QPainter *painter,const QRectF &rect); //完成地图显示的功能
void mouseMoveEvent(QMouseEvent * event);
private:
qreal zoom;
QLabel *viewCoord;
QLabel *sceneCoord;
QLabel *mapCoord;
double x1,x2;
double y1,y2;
};
#endif // MAPWIDGET_H
mapwidget.cpp
#include "mapwidget.h"
#include <QSlider>
#include <QGridLayout>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QFile>
#include <QGraphicsScene>
#include <QTextStream>
#include <math.h>
#include <QLabel>
/* 1、setCacheMode(CacheBackground)这个属性控制view的那一部分缓存中,QGraphicsView可以预存一些内容在QPixmap中,
* 然后被绘制到viewpoint上,这样做的目的是加速整体区域重绘的速度,例如:质地、倾斜度、和最初的混合背景可能重绘很缓慢,
* 尤其是在一个变形的view中,CacheBackground标志使能view的背景缓存,例如
* QGraphicsView view;
* view.setBackgroundBrush(QImage(":/images/backgroundtile.png"));
* view.setCacheMode(QGraphicsView::CacheBackground);
* 每次view转换后cache就无效了,然而,当滚动区域时候,只有部分无效默认的,没有使用cache
* 2、setTickInterval(int)来设置发射信号的间隔,一般都设置为1000ms,就是1s发射一次
* 3、setScaledContents(bool)这个属性保存标签是否按这个图片的比例填满所用的可用空间,默认false*/
MapWidget::MapWidget()
{
//读取地图信息,包括地图的名称,经纬度等
readMap();
zoom=50;
int width=map.width();
int height=map.height();
QGraphicsScene *scene=new QGraphicsScene(this);
scene->setSceneRect(-width/2,-height/2,width,height);
setScene(scene);
setCacheMode(CacheBackground);
//用于地图缩放的滑动条
QSlider *slider=new QSlider;
slider->setOrientation(Qt::Vertical);
slider->setRange(1,100);
slider->setTickInterval(10);
slider->setValue(1);
connect(slider,&QSlider::valueChanged,[=](int t_value){slotZoom(t_value);});;
QLabel *zoomin=new QLabel;
zoomin->setScaledContents(true);
zoomin->setPixmap(QPixmap(":/image/zoomin.jpg"));
zoomin->setFixedSize(30,30);
QLabel *zoomout=new QLabel;
zoomout->setScaledContents(true );
zoomout->setPixmap(QPixmap(":/image/zoomout.jpg"));
zoomout->setFixedSize(30,30);
//坐标值显示区
QLabel *label1=new QLabel(QStringLiteral("QGraphicsView:"));
viewCoord=new QLabel;
QLabel *label2=new QLabel(QStringLiteral("QGraphicsScene:"));
sceneCoord=new QLabel;
QLabel *label3=new QLabel(QStringLiteral("map:"));
mapCoord=new QLabel;
//坐标显示区布局
QGridLayout *gridLayout=new QGridLayout;
gridLayout->addWidget(label1,0,0);
gridLayout->addWidget(viewCoord,0,1);
gridLayout->addWidget(label2,1,0);
gridLayout->addWidget(sceneCoord,1,1);
gridLayout->addWidget(label3,2,0);
gridLayout->addWidget(mapCoord,2,1);
gridLayout->setSizeConstraint(QLayout::SetFixedSize);
QFrame *coordFrame=new QFrame;
coordFrame->setLayout(gridLayout);
//坐标显示布局
QVBoxLayout *coordLayout=new QVBoxLayout;
coordLayout->addWidget(coordFrame);
coordLayout->addStretch();
//缩放控制子布局
QVBoxLayout *zoomlayout=new QVBoxLayout;
zoomlayout->addWidget(zoomin);
zoomlayout->addWidget(slider);
zoomlayout->addWidget(zoomout);
//主布局
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addLayout(zoomlayout);
mainLayout->addLayout(coordLayout);
mainLayout->addStretch();
mainLayout->setMargin(30);
mainLayout->setSpacing(10);
setLayout(mainLayout);
setWindowTitle(QStringLiteral("Map Widget"));
setMinimumSize(600,400);
}
void MapWidget::readMap() //读取地图信息
{
QString mapName;
QFile mapFile(":/image/China.txt");
int ok=mapFile.open((QIODevice::ReadOnly | QIODevice::Text)); //以"只读"方式打开此文件
if(ok)
{
QTextStream ts(&mapFile);
if(!ts.atEnd())
{
ts >> mapName;
ts>>x1>>y1>>x2>>y2;
}
}
mapFile.close();
map.load(":/image/China.jpg"); //将地图读取至私有变量map中
}
//根据缩放滑动条的当前值,确定当前缩放的比例
void MapWidget::slotZoom(int value)
{
/*
* 检测value(slider改变得到的值),与当前value值得大小比较
* pow(x, y)表示x的y次方
* slider改变的值大于zoom值时,增加缩放比例
* slider改变的值小于zoom值时,减小缩放比例
* scale(s, s)将当前的视图换为(s, s)
*/
qreal s;
if(value>zoom) //放大
{
s=pow(1.01,(value-zoom));
}
else
{
s=pow(1/1.01,(zoom-value));
}
scale(s,s); //实现地图的缩放
zoom=value;
}
//以地图图片重绘场景的背景来实现地图显示
void MapWidget::drawBackground(QPainter *painter, const QRectF &rect)
{
painter->drawPixmap(int(sceneRect().left()),int(sceneRect().top()),map);
}
//完成某点在坐标上的映射和显示
void MapWidget::mouseMoveEvent(QMouseEvent *event)
{
//QGraphicsView坐标
QPoint viewpoint=event->pos();
viewCoord->setText(QString::number(viewpoint.x())+","+QString::number(viewpoint.y()));
//QGraphicsScene坐标
QPointF scenePoint=mapToScene(viewpoint);
sceneCoord->setText(QString::number(scenePoint.x())+","+QString::number(scenePoint.y()));
//地图坐标(经纬度)
QPointF latLon= mapToMap(scenePoint);
mapCoord->setText(QString::number(latLon.x())+","+QString::number(latLon.y()));
}
QPointF MapWidget::mapToMap(QPointF p)
{
QPointF latLon;
qreal w=sceneRect().width();
qreal h=sceneRect().height();
qreal lon=y1-((h/2+p.y())*abs(y1-y2)/h);
qreal lat=y1-((w/2+p.x())*abs(x1-x2)/w);
latLon.setX(lat);
latLon.setY(lon);
return latLon;
}