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
View Code

 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 }
View Code

 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
View Code

 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 }
View Code

 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>
View Code

 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
View Code

 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 }
View Code

 

 

posted on 2023-01-10 18:55  疯狂delphi  阅读(115)  评论(0编辑  收藏  举报

导航