Qt-Qt之实现框选地图功能(返回选中区域经纬度)
.pro
1 QT += core gui 2 3 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 4 5 CONFIG += c++11 6 7 # The following define makes your compiler emit warnings if you use 8 # any Qt feature that has been marked deprecated (the exact warnings 9 # depend on your compiler). Please consult the documentation of the 10 # deprecated API in order to know how to port your code away from it. 11 DEFINES += QT_DEPRECATED_WARNINGS 12 13 # You can also make your code fail to compile if it uses deprecated APIs. 14 # In order to do so, uncomment the following line. 15 # You can also select to disable deprecated APIs only up to a certain version of Qt. 16 #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 17 18 SOURCES += \ 19 BoxSelectWidget.cpp \ 20 main.cpp \ 21 mainwindow.cpp 22 23 HEADERS += \ 24 BoxSelectWidget.h \ 25 mainwindow.h 26 27 FORMS += \ 28 mainwindow.ui 29 30 # Default rules for deployment. 31 qnx: target.path = /tmp/$${TARGET}/bin 32 else: unix:!android: target.path = /opt/$${TARGET}/bin 33 !isEmpty(target.path): INSTALLS += target 34 35 RESOURCES += \ 36 rcs.qrc
main.cpp
1 #include "mainwindow.h" 2 3 #include <QApplication> 4 5 int main(int argc, char *argv[]) 6 { 7 QApplication a(argc, argv); 8 MainWindow w; 9 w.show(); 10 return a.exec(); 11 }
mainwindow.h
1 #ifndef MAINWINDOW_H 2 #define MAINWINDOW_H 3 4 #include <QMainWindow> 5 #include <QTimer> 6 7 #include "BoxSelectWidget.h" 8 9 QT_BEGIN_NAMESPACE 10 namespace Ui { class MainWindow; } 11 QT_END_NAMESPACE 12 13 class MainWindow : public QMainWindow 14 { 15 Q_OBJECT 16 public: 17 MainWindow(QWidget *parent = nullptr); 18 ~MainWindow(); 19 20 private: 21 void on_GetLonLat(); 22 23 Ui::MainWindow *ui; 24 TBoxSelectWidget *m_Box; 25 QTimer *m_pTimer; 26 }; 27 28 29 #endif // MAINWINDOW_H
mainwindow.cpp
1 #include "mainwindow.h" 2 #include "ui_mainwindow.h" 3 4 const QString C_Title = QStringLiteral("Qt之实现框选地图功能 %1 %2 %3 %4"); 5 6 MainWindow::MainWindow(QWidget *parent) 7 : QMainWindow(parent) 8 , ui(new Ui::MainWindow) 9 { 10 ui->setupUi(this); 11 12 setWindowTitle(C_Title); 13 this->setFixedSize(534, 600);// 中国版图宽度970 高度1120 宽高比例8.9 14 // 中国经度范围:73°33′E至135°05′E;纬度范围:3°51′N至53°33′N。 15 // 73°33′E = 73.55 16 // 135°05′E = 135.083 17 // 3°51′N = 3.85 18 // 53°33′N = 53.55 19 m_Box = new TBoxSelectWidget(this->width(), this->height(), 20 73.55, 135.083, 21 3.85, 53.55, 22 ":/new/image/map.jpg", this); 23 24 m_pTimer = new QTimer(this); 25 m_pTimer->setSingleShot(false); 26 m_pTimer->start(100); 27 connect(m_pTimer, &QTimer::timeout, this, &MainWindow::on_GetLonLat); 28 } 29 30 MainWindow::~MainWindow() 31 { 32 delete ui; 33 } 34 35 void MainWindow::on_GetLonLat() 36 { 37 setWindowTitle(C_Title.arg(m_Box->getMinLon()) 38 .arg(m_Box->getMaxLon()) 39 .arg(m_Box->getMinLat()) 40 .arg(m_Box->getMaxLat())); 41 42 }
mainwindow.ui
1 <?xml version="1.0" encoding="UTF-8"?> 2 <ui version="4.0"> 3 <class>MainWindow</class> 4 <widget class="QMainWindow" name="MainWindow"> 5 <property name="geometry"> 6 <rect> 7 <x>0</x> 8 <y>0</y> 9 <width>600</width> 10 <height>600</height> 11 </rect> 12 </property> 13 <property name="windowTitle"> 14 <string>MainWindow</string> 15 </property> 16 <widget class="QWidget" name="centralwidget"/> 17 </widget> 18 <resources/> 19 <connections/> 20 </ui>
BoxSelectWidget.h
1 // 作者:朱建强 时间:2023-01-10 2 // 支持点选(鼠标左键单格点) 3 // 支持框选(左上TO右下) 4 // 支持正负框选(框选上次选中的将变为非选中) 5 // 支持模糊框选(左上TO右下、右下TO左上) 6 // 支持反选(选中TO非选中) 7 // 支持立即显示 8 #ifndef BOXSELECTWIDGET_H 9 #define BOXSELECTWIDGET_H 10 11 #include <QWidget> 12 #include <QPainter> 13 #include <QMouseEvent> 14 #include <QDebug> 15 #include <QVector> 16 17 class TBoxSelectWidget : public QWidget 18 { 19 Q_OBJECT 20 public: 21 TBoxSelectWidget(int w, int h, 22 double mapMinLon, double mapMaxLon, 23 double mapMinLat, double mapMaxLat, 24 QString mapImageFile, 25 QWidget* parent = nullptr); 26 ~TBoxSelectWidget(); 27 28 double getMinLon(); 29 double getMaxLon(); 30 double getMinLat(); 31 double getMaxLat(); 32 protected: 33 virtual void paintEvent(QPaintEvent *event); 34 virtual void mousePressEvent(QMouseEvent *event); 35 virtual void mouseReleaseEvent(QMouseEvent *event); 36 virtual void mouseMoveEvent(QMouseEvent *event); 37 private: 38 void addMouseXY(int x, int y);// 增加鼠标点 39 void setArrayNull(bool value);// 数据给O 40 void getCellWidhtHeight();// 计算格子的长宽 41 void getCellLonLat();// 计算格子的经纬度 42 void drawCell(QPainter &painter);// 根据数据绘制格子 43 void drawGrid(QPainter &painter, int x, int y);// 绘制网格 44 // 计算用 45 bool getMouseXYToArrayIndex(int x, int y, int x2, int y2); 46 void getSelectLonLat();// 计算选中区域 47 // 地图经纬区域 48 double m_dMapMinLon = 0; 49 double m_dMapMaxLon = 0; 50 double m_dMapMinLat = 0; 51 double m_dMapMaxLat = 0; 52 QString m_sMapImageFile = ""; 53 // 输出选中的经纬度 54 double m_dSelectMinLon = 0; 55 double m_dSelectMaxLon = 0; 56 double m_dSelectMinLat = 0; 57 double m_dSelectMaxLat = 0; 58 // 鼠标位置 59 int m_nXBeing = 0; 60 int m_nYBeing = 0; 61 int m_nX = 0; 62 int m_nY = 0; 63 // 行列变量 64 int m_nRow = 10; 65 int m_nCol = 10; 66 // 每一个格子的长与宽 67 int m_CellWidth = 0; 68 int m_CellHeight = 0; 69 // 每一个格子的经度与纬度 70 double m_CellLon = 0.0; 71 double m_CellLat = 0.0; 72 // 选中数组 73 QVector<QVector<bool>> m_Array; 74 // 框选模式 75 int m_nSelectMode = 2;// 黙认:单选、1:左上TO右下框选、2:模糊框选 76 // 多区域模式 77 int m_nMultizoneMode = 0;// 黙认:不支持多区域、1:支持多区域 78 // 选中效果立即显示 79 int m_nRealTimeShowMode = 1;// 默认:最后显示、1:立即显示 80 // 框选异形区域 81 int m_nShapeMode = 0;// 默认:不支持异形、1:支持异形 82 83 }; 84 85 86 #endif // BOXSELECTWIDGET_H
BoxSelectWidget.cpp
1 #include "BoxSelectWidget.h" 2 3 TBoxSelectWidget::TBoxSelectWidget(int w, int h, double mapMinLon, double mapMaxLon, double mapMinLat, double mapMaxLat, QString mapImageFile, QWidget *parent) 4 :QWidget(parent), 5 m_dMapMinLon(mapMinLon), 6 m_dMapMaxLon(mapMaxLon), 7 m_dMapMinLat(mapMinLat), 8 m_dMapMaxLat(mapMaxLat), 9 m_sMapImageFile(mapImageFile) 10 { 11 this->setGeometry(0, 0, w, h); 12 setArrayNull(false); 13 getCellWidhtHeight(); // 计算每格长宽 14 getCellLonLat();// 计算每个格子的经度与纬度 15 } 16 17 TBoxSelectWidget::~TBoxSelectWidget() 18 { 19 20 } 21 22 double TBoxSelectWidget::getMinLon() 23 { 24 return m_dSelectMinLon; 25 } 26 27 double TBoxSelectWidget::getMaxLon() 28 { 29 return m_dSelectMaxLon; 30 } 31 32 double TBoxSelectWidget::getMinLat() 33 { 34 return m_dSelectMinLat; 35 } 36 37 double TBoxSelectWidget::getMaxLat() 38 { 39 return m_dSelectMaxLat; 40 } 41 42 void TBoxSelectWidget::paintEvent(QPaintEvent *event) 43 { 44 // 界面背景图片片 45 QPainter painter(this); 46 painter.drawPixmap(0, 0, this->width(), this->height(), QPixmap(m_sMapImageFile)); 47 48 painter.setPen(Qt::red); 49 int nXBeing; 50 int nYBeing; 51 int nXEnd; 52 int nYEnd; 53 54 // 绘制行 55 for (int i = 1; i < m_nCol; ++i) 56 { 57 nXBeing = 0; 58 nYBeing = this->height() / m_nCol * i; 59 nXEnd = this->width(); 60 nYEnd = nYBeing; 61 62 painter.drawLine(nXBeing, nYBeing, nXEnd, nYEnd); 63 } 64 // 绘制列 65 for (int i = 1; i < m_nRow; ++i) 66 { 67 nXBeing = this->width() / m_nRow * i; 68 nYBeing = 0; 69 nXEnd = nXBeing; 70 nYEnd = this->height(); 71 72 painter.drawLine(nXBeing, nYBeing, nXEnd, nYEnd); 73 } 74 // 根据选中的数组显示红线 75 drawCell(painter); 76 // 计算输出经纬度值 77 getSelectLonLat(); 78 } 79 80 void TBoxSelectWidget::mousePressEvent(QMouseEvent *event) 81 { 82 m_nX = event->x(); 83 m_nY = event->y(); 84 m_nXBeing = m_nX; 85 m_nYBeing = m_nY; 86 87 if(0 == m_nMultizoneMode) 88 setArrayNull(false); 89 90 this->repaint(); 91 } 92 93 void TBoxSelectWidget::mouseReleaseEvent(QMouseEvent *event) 94 { 95 m_nX = event->x(); 96 m_nY = event->y(); 97 98 getMouseXYToArrayIndex(m_nXBeing, m_nYBeing, m_nX, m_nY); 99 this->repaint(); 100 } 101 102 void TBoxSelectWidget::mouseMoveEvent(QMouseEvent *event) 103 { 104 m_nX = event->x(); 105 m_nY = event->y(); 106 107 if(1 == m_nRealTimeShowMode) 108 { 109 getMouseXYToArrayIndex(m_nXBeing, m_nYBeing, m_nX, m_nY); 110 this->repaint(); 111 } 112 } 113 114 void TBoxSelectWidget::addMouseXY(int x, int y) 115 { 116 117 } 118 119 void TBoxSelectWidget::setArrayNull(bool value) 120 { 121 m_Array.resize(m_nRow); 122 for(int j = 0; j< m_Array.size(); j++) 123 { 124 m_Array[j].resize(m_nCol); 125 } 126 127 for(int i = 0; i < m_nRow; ++i) 128 { 129 for(int j = 0; j < m_nCol; ++j) 130 { 131 m_Array[i][j] = value; 132 } 133 } 134 // 135 // m_Array[0][9] = true; 136 // m_Array[5][8] = 1; 137 138 } 139 140 void TBoxSelectWidget::getCellWidhtHeight() 141 { 142 m_CellWidth = this->width() / m_nCol; 143 m_CellHeight = this->height() / m_nRow; 144 } 145 146 void TBoxSelectWidget::getCellLonLat() 147 { 148 m_CellLon = qAbs(m_dMapMinLon - m_dMapMaxLon) / m_nCol; 149 m_CellLat = qAbs(m_dMapMinLat - m_dMapMaxLat) / m_nRow; 150 } 151 152 void TBoxSelectWidget::drawCell(QPainter &painter) 153 { 154 for(int i = 0; i < m_Array.size(); ++i) 155 { 156 for(int j = 0; j < m_Array[i].size(); ++j) 157 { 158 if (true == m_Array[i][j]) 159 drawGrid(painter, i, j); 160 } 161 } 162 } 163 164 void TBoxSelectWidget::drawGrid(QPainter &painter, int x, int y) 165 { 166 int x1, y1, x2, y2; 167 x1 = m_CellWidth * y; 168 x2 = m_CellWidth * (y + 1); 169 y1 = m_CellHeight * x; 170 y2 = m_CellHeight * (x + 1); 171 172 painter.setPen(Qt::blue); 173 for(int i = y1 + 5; i < y2; i+=5) 174 { 175 painter.drawLine(x1, i, x2, i); 176 } 177 for(int i = x1 + 5; i < x2; i+=5) 178 { 179 painter.drawLine(i, y1, i, y2); 180 } 181 } 182 183 bool TBoxSelectWidget::getMouseXYToArrayIndex(int x, int y, int x2, int y2) 184 { 185 // 计算前的x、y 186 int nX1, nY1, nX2, nY2; 187 if(0 == m_nSelectMode) 188 { 189 nX1 = x; 190 nY1 = y; 191 nX2 = nX1; 192 nY2 = nY1; 193 } 194 else if (1 == m_nSelectMode) 195 { 196 nX1 = x; 197 nY1 = y; 198 nX2 = x2; 199 nY2 = y2; 200 } 201 else if(2 == m_nSelectMode) 202 { 203 nX1 = qMin(x, x2); 204 nY1 = qMin(y, y2); 205 nX2 = qMax(x, x2); 206 nY2 = qMax(y, y2); 207 } 208 // 计算后的行列 209 int nRBeing, nCBeing; 210 int nREnd, nCEnd; 211 if (nX1 == nX2 && nY1 == nY2) // 单选 212 { 213 nRBeing = nY1 % m_CellHeight > 0 ? nY1 / m_CellHeight : nY1 / m_CellHeight + 1; 214 nCBeing = nX1 % m_CellWidth > 0 ? nX1 / m_CellWidth : nX1 / m_CellWidth + 1; 215 // 处理BUG,数组越界 216 nRBeing = qMin(nRBeing, m_nRow -1); 217 nCBeing = qMin(nCBeing, m_nCol -1); 218 219 m_Array[nRBeing][nCBeing] = !m_Array[nRBeing][nCBeing]; 220 return true; 221 } 222 else // 多选 223 { 224 nRBeing = nY1 % m_CellHeight > 0 ? nY1 / m_CellHeight : nY1 / m_CellHeight; 225 nCBeing = nX1 % m_CellWidth > 0 ? nX1 / m_CellWidth : nX1 / m_CellWidth; 226 227 nREnd = nY2 % m_CellHeight > 0 ? nY2 / m_CellHeight : nY2 / m_CellHeight; 228 nCEnd = nX2 % m_CellWidth > 0 ? nX2 / m_CellWidth: nX2 / m_CellWidth; 229 // 处理BUG,数组越界 230 nRBeing = qMin(nRBeing, m_nRow -1); 231 nCBeing = qMin(nCBeing, m_nCol -1); 232 nREnd = qMin(nREnd, m_nRow -1); 233 nCEnd = qMin(nCEnd, m_nCol -1); 234 // 235 if (0 == m_nShapeMode) 236 { 237 setArrayNull(false); 238 } 239 for(int i = 0; i < m_Array.size(); ++i) 240 { 241 for(int j = 0; j < m_Array[i].size(); ++j) 242 { 243 if ((i <= nREnd && i >= nRBeing) && (j <= nCEnd && j >= nCBeing)) 244 { 245 if(1 == m_nRealTimeShowMode) 246 m_Array[i][j] = 1; 247 else 248 m_Array[i][j] = !m_Array[i][j]; 249 } 250 } 251 } 252 return false; 253 } 254 } 255 256 void TBoxSelectWidget::getSelectLonLat() 257 { 258 m_dSelectMinLon = 0; 259 m_dSelectMaxLon = 0; 260 m_dSelectMinLat = 0; 261 m_dSelectMaxLat = 0; 262 int nSelectMinRow = -1; 263 int nSelectMaxRow = -1; 264 int nSelectMinCol = -1; 265 int nSelectMaxCol = -1; 266 for(int i = 0; i < m_Array.size(); ++i) 267 { 268 for(int j = 0; j < m_Array[i].size(); ++j) 269 { 270 if (true == m_Array[i][j]) 271 { 272 if(-1 == nSelectMinRow) 273 { 274 nSelectMinRow = i; 275 nSelectMaxRow = i; 276 } 277 else 278 nSelectMaxRow = i; 279 if(-1 == nSelectMinCol) 280 { 281 nSelectMinCol = j; 282 nSelectMaxCol = j; 283 } 284 else 285 nSelectMaxCol = j; 286 } 287 } 288 } 289 // 计算出最后的经纬度 290 if (-1 == nSelectMinRow || -1 == nSelectMinCol) 291 return; 292 m_dSelectMinLon = m_dMapMinLon + m_CellLon * nSelectMinCol; 293 m_dSelectMaxLon = m_dMapMinLon + m_CellLon * (nSelectMaxCol + 1); 294 m_dSelectMinLat = m_dMapMaxLat - m_CellLat * (nSelectMaxRow + 1); 295 m_dSelectMaxLat = m_dMapMaxLat - m_CellLat * nSelectMinRow; 296 qDebug() << 297 "m_dSelectMinLon:" << m_dSelectMinLon << 298 "m_dSelectMaxLon:" << m_dSelectMaxLon << 299 "m_dSelectMinLat:" << m_dSelectMinLat << 300 "m_dSelectMaxLat:" << m_dSelectMaxLat; 301 }
作者:疯狂Delphi
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
欢迎关注我,一起进步!扫描下方二维码即可加我