QT+VS調用高德地圖的JS API實現地圖打點小工具


1.QT的WebEngineView模塊+VS 的msvc編譯器+高德地圖的JS API實現,效果如圖:

 

 

 2.程序源碼:

QT的pro文件需要加上一行

QT += webengine webenginewidgets webchannel widgets

(1)amapmarktools.html,主要用於顯示網頁,以及調用高德的JS API進行交互

<!DOCTYPE html>
<html>  
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
        <title>高德地圖打點小工具</title>
        <script type="text/javascript" src="https://webapi.amap.com/maps?v=2.0&key=你在高德地圖申請的key"></script>
        <style>
        *{
            margin: 0;
            padding: 0;
        }
        #container
        {
            width: 100%;
            height: 100%;
            position: absolute;
            left: 0;
            top:0;
        }
        </style>
    </head>

    <body>
        <div id="container"></div>
        <script>
           
        </script>
    </body>
</html>
<script src="qwebchannel.js"></script>//與qt交互需要用到,在本文件同一目錄下
<script type="text/javascript">
        var map = new AMap.Map("container",{zoom:14,center:[113.324,23.106]});
        var MarkIconpath;
        var amap_bridge;
        new QWebChannel(qt.webChannelTransport, function (channel) {
            amap_bridge = channel.objects.amap_bridge;  //bridge_name 與QT 中一致
    });
        var AuthorName=amap_bridge.GetAMapAuthorName();
        function getMarkerIconpath(icon_path)
         {
            MarkIconpath=icon_path;
         }
        function addOneMarker(lat, lng,titleName)
         {
            //GPS轉高德坐標
            var gps = [parseFloat(lng),parseFloat(lat)];
            if(titleName=="")
            {
                titleName="undefine_markname";
            }
            AMap.convertFrom(gps, 'gps', function (status, result) 
            {
                if (result.info === 'ok')
                {
                    var lnglats= result.locations; // Array.<LngLat>
                    var marker = new AMap.Marker(
                            {   position:lnglats[0], // 經緯度對象,也可以是經緯度構成的一維數組[116.39, 39.9]
                                title:titleName,
                                icon:MarkIconpath,
                            });
                    marker.setClickable(true);
                    marker.on("rightclick", function (e){
                        if (confirm('確定要刪除嗎') == true) 
                        {
                            map.remove(marker);
                            return true;
                        } 
                        else
                        {
                            return false;
                        }
                    },"rightclick");
                    marker.setMap(map);
                    map.setCenter(lnglats[0]);
                 }
            });
        }
        function removeAllMark()
        {
            map.clearMap();
        }
        function saveMarkToFile()
        {
            var markeroverlaysList = map.getAllOverlays('marker'); 
            for(var i=0;i<markeroverlaysList.length;i++)
            {
                var position=markeroverlaysList[i].getPosition();
                var title=markeroverlaysList[i].getTitle();
                amap_bridge.saveAllMarkToFileFromAMap(position.lat,position.lng,title);
                
            }
        }

</script>

(2)qwebchannel.js,建立qt應用與html的數據交互,本文件由qt官方提供。

地址:https://doc.qt.io/qt-5.9/qtwebengine-webenginewidgets-markdowneditor-resources-qwebchannel-js.html

(3)amapmainwindow.cpp,用於調用WebEngineView,建立與html的數據交互,以及界面顯示等.

#pragma execution_character_set("utf-8")//防止中文亂碼,並且需要用Notepad++把本文件的編碼格式改為ucs-2 Little endian
#include "amapmainwindow.h"
#include "ui_amapmainwindow.h"
#include <QNetworkProxyFactory>
#include<QDoubleValidator>
#include <QSize>
#include<QFileDialog>
#include<QTextStream>
AMapMainWindow::AMapMainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::AMapMainWindow)
{
    ui->setupUi(this);
    setWindowTitle("AMapMarkTools地圖打點小工具");
    p_AmapViewWedget = new QMainWindow();//用於放置webView
    p_AmapView=new QWebEngineView(p_AmapViewWedget);//將QWebEngineView的父Widget為p_AmapViewWedget
    p_AmapChannel = new QWebChannel(p_AmapView->page());   //創建通道,與JS交互
    p_AmapBridge=new JSWebBridge(p_AmapViewWedget); //創建通道,與JS交互
    p_AmapChannel->registerObject("amap_bridge",(QObject*)p_AmapBridge);// 注冊名"amap_bridge"與JS中用到的名稱保持相同
    p_AmapView->page()->setWebChannel(p_AmapChannel);//View與chanel建立連接關系
    p_AmapViewWedget->setCentralWidget(p_AmapView);
    p_AmapHLayoutWidget = new QWidget(this);//用於將webView放置在AMapMainWindow
    p_AmapHLayoutWidget->setObjectName(QString::fromUtf8("p_AmapHLayoutWidget"));
    p_AmapHLayoutWidget->setGeometry(QRect(0, 0, 720, 480));//窗口大小為720*480
    p_AmapHLayoutWidget->move(150,0);
    p_AmapHLayout=new QHBoxLayout(p_AmapHLayoutWidget);
    p_AmapHLayout->addWidget((QWidget *)p_AmapViewWedget);
    setLayout(p_AmapHLayout);
    QNetworkProxyFactory::setUseSystemConfiguration(false);//不用代理
    QString htmlFilePath =QApplication::applicationDirPath()+"/amapmarktools.html";
    loadMarkFilePath=QApplication::applicationDirPath();
    p_AmapView->page()->load(QUrl(htmlFilePath));
    p_AmapView->page()->setBackgroundColor(Qt::transparent);//背景透明
    this->setMinimumWidth(720);
    this->setMinimumHeight(480);
    p_operaterLayoutWidget=new QWidget(this);
    p_addOneMark=new QPushButton(p_operaterLayoutWidget);
    p_addOneMark->setFixedSize(QSize(100,30));
    p_addOneMark->setText("增加標記");
    p_addMarkFromFile=new QPushButton(p_operaterLayoutWidget);
    p_addMarkFromFile->setFixedSize(QSize(100,30));
    p_addMarkFromFile->setText("從文件導入標記");
    p_removeAllMark=new QPushButton(p_operaterLayoutWidget);
    p_removeAllMark->setFixedSize(QSize(100,30));
    p_removeAllMark->setText("刪除所有標記");
    p_saveAllMarkToFile=new QPushButton(p_operaterLayoutWidget);
    p_saveAllMarkToFile->setFixedSize(QSize(100,30));
    p_saveAllMarkToFile->setText("導出所有標記");
    p_operaterLayout=new QVBoxLayout(p_operaterLayoutWidget);
    p_operaterLayoutWidget->setGeometry(QRect(0, 0, 200, 480));
    p_operaterLayoutWidget->move(0,0);
    latLineEdit=new QLineEdit(p_operaterLayoutWidget);
    lngLineEdit=new QLineEdit(p_operaterLayoutWidget);
    nameLineEdit=new QLineEdit(p_operaterLayoutWidget);
    latLineEdit->setFixedSize(QSize(100,20));
    latLineEdit->setPlaceholderText("gps維度:23.4");
    lngLineEdit->setFixedSize(QSize(100,20));
    lngLineEdit->setPlaceholderText("gps經度:123.4");
    nameLineEdit->setFixedSize(QSize(100,20));
    nameLineEdit->setPlaceholderText("標記名稱(可選)");
    QDoubleValidator *validator = new QDoubleValidator(0, 360, 10, this);
    lngLineEdit->setValidator(validator);
    latLineEdit->setValidator(validator);
    p_operaterLayout->addWidget(latLineEdit);
    p_operaterLayout->addWidget(lngLineEdit);
    p_operaterLayout->addWidget(nameLineEdit);
    p_operaterLayout->addWidget(p_addOneMark);
    p_operaterLayout->addWidget(p_addMarkFromFile);
    p_operaterLayout->addWidget(p_saveAllMarkToFile);
    p_operaterLayout->addWidget(p_removeAllMark);
    setLayout(p_operaterLayout);
    p_operaterLayout->setAlignment(Qt::AlignJustify);
    connect(p_addOneMark, SIGNAL(clicked()),this, SLOT(addOneMarkBtnClickEvent()));
    connect(p_removeAllMark, SIGNAL(clicked()),this, SLOT(removeAllMarkBtnClickEvent()));
    connect(p_addMarkFromFile, SIGNAL(clicked()),this, SLOT(addMarkFromFileBtnClickEvent()));
    connect(p_saveAllMarkToFile, SIGNAL(clicked()),this, SLOT(saveAllMarkToFileBtnClickEvent()));
}

AMapMainWindow::~AMapMainWindow()
{
    delete ui;
}

void AMapMainWindow::resizeEvent(QResizeEvent* size)
{
    QSize m_size= this->size();
    p_AmapHLayoutWidget->setGeometry(QRect(0, 0, m_size.width()-150,m_size.height()));//窗口大小為720*480
    p_AmapHLayoutWidget->move(150,0);
    p_operaterLayoutWidget->setGeometry(QRect(0, 0, 150, m_size.height()));
    p_operaterLayoutWidget->move(0,0);
}
void AMapMainWindow::addOneMark(double lat,double lng,QString labelname)
{
    QString latStr = QString::number(lat, 10, 6);
    QString lngStr = QString::number(lng, 10, 6);
    QString jsCmd=QString("addOneMarker('%1','%2','%3')").arg(latStr).arg(lngStr).arg(labelname);
    qDebug()<<jsCmd;
    p_AmapView->page()->runJavaScript(jsCmd);
}

void AMapMainWindow::addOneMarkBtnClickEvent()
{
      qDebug()<<"addOneMarkBtnClickEvent";
      if((lngLineEdit->text().length()<1)||(latLineEdit->text().length()<1))
          return;

      double longtitude=lngLineEdit->text().toDouble();
      double latitude=latLineEdit->text().toDouble();
      if(nameLineEdit->text().length()>=1)
      {
          addOneMark(latitude,longtitude,nameLineEdit->text());
      }
      else
      {
          addOneMark(latitude,longtitude,"");
      }

      getMarkerIconpath((QApplication::applicationDirPath()+"/markerIcon.png"));
}
void AMapMainWindow::removeAllMarkBtnClickEvent()
{
    removeAllMark();
}
void AMapMainWindow::getMarkerIconpath(QString path)
{
    static bool setFlg=false;

    if(setFlg==false)
    {
        QString jsCmd=QString("getMarkerIconpath('%1')").arg(path);
        qDebug()<<jsCmd;
        p_AmapView->page()->runJavaScript(jsCmd);
        setFlg=true;
    }

}
void  AMapMainWindow::removeAllMark()
{
    QString jsCmd=QString("removeAllMark()");
    qDebug()<<jsCmd;
    p_AmapView->page()->runJavaScript(jsCmd);
}

void AMapMainWindow::addMarkFromFileBtnClickEvent()
{
     getMarkerIconpath((QApplication::applicationDirPath()+"/markerIcon.png"));
    QFileDialog fileDialog(this);
    fileDialog.setWindowTitle(tr("打開文件"));
    fileDialog.setDirectory(loadMarkFilePath);
    fileDialog.setNameFilter(tr("*.txt *.log *.*"));
    fileDialog.setFileMode(QFileDialog::ExistingFiles);
    fileDialog.setViewMode(QFileDialog::Detail);
    //fileDialog.setGeometry(200,200,300,300);
    if(fileDialog.exec() == QDialog::Accepted)
    {
        QString path = fileDialog.selectedFiles()[0];//select first filename
        fileDialog.close();
        QFile rfile(path);
        if(rfile.open(QIODevice::ReadOnly)== true)
        {

            QTextStream readTextStream(&rfile); //創建輸出流
            while(!readTextStream.atEnd())
            {
                double lng=-1;
                double lat=-1;
                QString markName;
                QString oneLineText = readTextStream.readLine();  //讀取一行
                QString tmpText=oneLineText;
                int i=0;
                do
                {
                    if(i>2)
                        break;
                    if((tmpText.contains(",")))
                    {

                        tmpText=oneLineText.section(',', (i)).trimmed();
                        qDebug()<<"i="<<i<<",tmpText"<<tmpText;
                        bool isOk=false;
                            switch (i)
                            {
                            case 0:

                                oneLineText.section(',', i,i).trimmed().toDouble(&isOk);
                                if(isOk)
                                {
                                 lng=oneLineText.section(',', i,i).trimmed().toDouble();
                                 qDebug()<<"經度:"<<lng;
                                }
                                break;
                            case 1:
                                 oneLineText.section(',', i,i).trimmed().toDouble(&isOk);
                                 if(isOk)
                                 {
                                     lat=oneLineText.section(',', i,i).trimmed().toDouble();
                                     qDebug()<<"維度:"<<lat;
                                 }
                                break;
                            case 2:
                                markName=oneLineText.section(',', i,i).trimmed();
                                qDebug()<<"名字:"<<markName;
                                break;
                            default:
                                break;

                            }
                     }
                    i++;
                }while(tmpText.size()>0);
                if(lng>0&&lat>0)
                {
                    qDebug()<<"addOneMark"<<lat<<","<<lng<<","<<markName;
                    addOneMark(lat,lng,markName);
                }
            }

        }
    }

}
void AMapMainWindow::saveAllMarkToFile()
{

    QString jsCmd=QString("saveMarkToFile()");
    qDebug()<<jsCmd;
    p_AmapView->page()->runJavaScript(jsCmd);
}
void AMapMainWindow::saveAllMarkToFileBtnClickEvent()
{
    QString filename = QFileDialog::getSaveFileName(this,
        tr("選擇保存路徑"),
        "",
        tr("*.txt;; *.log;; *.csv;; *.*")); //選擇路徑
    if(filename.isEmpty())
    {
        return;
    }
    else
    {
        p_AmapBridge->saveAllMarkPath=filename;
        qDebug()<<(p_AmapBridge->saveAllMarkPath);
    }
    saveAllMarkToFile();
}

(4)jswebbridge.cpp,用於與html建立數據通道

#pragma execution_character_set("utf-8")//防止中文亂碼
#include "jswebbridge.h"
#include <QMutex>
#include <QFile>
static QMutex fileMutex;
JSWebBridge::JSWebBridge(QObject *parent) : QObject(parent)
{
    saveAllMarkPath="D:/";
}
QString JSWebBridge::GetAMapAuthorName()
{
    qDebug()<<"AuthorName:Jest";
    return "AuthorName:Jest";
}
void JSWebBridge::GetPointLatLngFromAMap(const QString lat,const QString lng,const QString name)
{
   qDebug()<<"來自web標記點輸出" <<"維度"<<lat<<","<<"經度"<<lng<<",名字"<<name;
}
void  JSWebBridge::saveAllMarkToFileFromAMap(QString lat,QString lng,QString labelname)
{
    fileMutex.lock();
    QFile file(saveAllMarkPath);
    if(file.open(QIODevice::WriteOnly | QIODevice::Text|QIODevice::Append))
    {
        QString tmp_str=lng+","+lat+","+labelname;
        QTextStream out(&file);
        out<<tmp_str<< endl;
        file.close();

    }
    fileMutex.unlock();
}

3.記錄幾個踩到的坑

(1)文件編碼為utf-8的源文件直接使用到中文會莫名報錯,用Notepad++把本文件的編碼格式改為ucs-2 Little endian,也可以用[tr("中文")]的方法。

(2)調用高德地圖增加mark時,默認圖標是只會顯示一個很小的壞圖片[x],就使用本地路徑圖片,這路徑是通過qt傳輸的。嘗試在AMapMainWindow構造函數傳遞此路徑,但由於建立數據通道初始化未完成,路徑沒有傳輸到html保存,還是壞圖片。所以在打點前會傳輸一次路徑,路徑才在html中保存

(3)在html中要加上這一句,指定調用什么js文件,否則html將無法調用qt中的函數。

<script src="qwebchannel.js"></script>//與qt交互需要用到,在本文件同一目錄下

(4)創建通道的步驟也要注意,還有注冊名要一致

 

 (5)使用高德地圖的JS API時,可以參考官方文檔、網上例子,可以在html中用alert函數進行測試數據是否正確

 

4.導入文本文件的數據格式

格式:經度,維度,mark的title名稱(可選)

例如:

113.2223,23.1111,mark1
113.2334,23.5644,
113.8223,23.9111,標記5

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM