c++ - 如何使用 Qt c++ QGeoServiceProvider 从地理地址获取纬度/经度?

标签 c++ qt geocoding

我正在尝试通过 QGeoServiceProvider 和 QGeoCodingManager 使用 osm api 从给定的物理地址导出纬度和经度。 因此我偶然发现了这个 Question ,这似乎正是我需要的。

但是我想在 qt gui 应用程序中将其作为一个单独的函数来实现,我不明白连接中发生了什么。 有人可以解释一下或者我如何修改它以使其在函数中工作吗?

    cout << "Try service: " << "osm" << endl;
    // choose provider
    QGeoServiceProvider qGeoService("osm");
    QGeoCodingManager *pQGeoCoder = qGeoService.geocodingManager();
    if (!pQGeoCoder) {
      cerr
        << "GeoCodingManager '" << "osm"
        << "' not available!" << endl;

    }
    QLocale qLocaleC(QLocale::C, QLocale::AnyCountry);
    pQGeoCoder->setLocale(qLocaleC);
    // build address
    QGeoAddress qGeoAddr;
    qGeoAddr.setCountry(QString::fromUtf8("Germany"));
    qGeoAddr.setPostalCode(QString::fromUtf8("88250"));
    qGeoAddr.setCity(QString::fromUtf8("Weingarten"));
    qGeoAddr.setStreet(QString::fromUtf8("Heinrich-Hertz-Str. 6"));
    QGeoCodeReply *pQGeoCode = pQGeoCoder->geocode(qGeoAddr);
    if (!pQGeoCode) {
      cerr << "GeoCoding totally failed!" << endl;

    }
    cout << "Searching..." << endl;
    QObject::connect(pQGeoCode, &QGeoCodeReply::finished,
      [&qGeoAddr, pQGeoCode](){
        cout << "Reply: " << pQGeoCode->errorString().toStdString() << endl;
        switch (pQGeoCode->error()) {
#define CASE(ERROR) \
case QGeoCodeReply::ERROR: cerr << #ERROR << endl; break
          CASE(NoError);
          CASE(EngineNotSetError);
          CASE(CommunicationError);
          CASE(ParseError);
          CASE(UnsupportedOptionError);
          CASE(CombinationError);
          CASE(UnknownError);
#undef CASE
          default: cerr << "Undocumented error!" << endl;
        }
        if (pQGeoCode->error() != QGeoCodeReply::NoError) return;
        // eval. result
        QList<QGeoLocation> qGeoLocs = pQGeoCode->locations();
        cout << qGeoLocs.size() << " location(s) returned." << endl;
        for (QGeoLocation &qGeoLoc : qGeoLocs) {
          qGeoLoc.setAddress(qGeoAddr);
          QGeoCoordinate qGeoCoord = qGeoLoc.coordinate();
          cout
            << "Lat.:  " << qGeoCoord.latitude() << endl
            << "Long.: " << qGeoCoord.longitude() << endl
            << "Alt.:  " << qGeoCoord.altitude() << endl;
        }
      });

所以我只是删除了 QApplication 部分,因为我在函数中没有这个引用。结果我得到:

Qt Version: 5.10.0
Try service: osm
Searching...

但没有坐标。我假设与获取纬度和经度数据的位置的连接失败。但正如我提到的,我不明白这里的联系。 感谢任何帮助

编辑 所以我试着建立一个连接来按照建议捕捉完成的信号。 代码现在看起来像这样:

QGeoServiceProvider qGeoService("osm");
  QGeoCodingManager *pQGeoCoder = qGeoService.geocodingManager();
  if (!pQGeoCoder) {
    cerr
      << "GeoCodingManager '" << "osm"
      << "' not available!" << endl;

  }
  QLocale qLocaleC(QLocale::C, QLocale::AnyCountry);
  pQGeoCoder->setLocale(qLocaleC);
  // build address
  //QGeoAddress qGeoAddr;
  qGeoAddr.setCountry(QString::fromUtf8("Germany"));
  qGeoAddr.setPostalCode(QString::fromUtf8("88250"));
  qGeoAddr.setCity(QString::fromUtf8("Weingarten"));
  qGeoAddr.setStreet(QString::fromUtf8("Heinrich-Hertz-Str. 6"));
  this->pQGeoCode = pQGeoCoder->geocode(qGeoAddr);
  if (!pQGeoCode) {
    cerr << "GeoCoding totally failed!" << endl;

  }
  cout << "Searching..." << endl;

  connect(pQGeoCode,SIGNAL(finished()),this,SLOT(getlonlat()));

插槽:

void MainWindow::getlonlat()
    {
      QList<QGeoLocation> qGeoLocs = pQGeoCode->locations();
                cout << qGeoLocs.size() << " location(s) returned." << endl;
                for (QGeoLocation &qGeoLoc : qGeoLocs) {
                  qGeoLoc.setAddress(qGeoAddr);
                  QGeoCoordinate qGeoCoord = qGeoLoc.coordinate();
                  cout
                    << "Lat.:  " << qGeoCoord.latitude() << endl
                    << "Long.: " << qGeoCoord.longitude() << endl
                    << "Alt.:  " << qGeoCoord.altitude() << endl;
                }
    }

然而,完成信号不会被触发。因此结果是一样的。 编辑

从您的 Gui 答案中实现代码:

主窗口.cpp:

#include "mainwindow.h"
#include "ui_mainwindow.h"

// standard C++ header:
#include <iostream>
#include <sstream>

// Qt header:
#include <QGeoAddress>
#include <QGeoCodingManager>
#include <QGeoCoordinate>
#include <QGeoLocation>
#include <QGeoServiceProvider>



MainWindow::MainWindow(QWidget *parent) :
  QMainWindow(parent),
  ui(new Ui::MainWindow)
{


  QGeoServiceProvider *pQGeoProvider = nullptr;

  ui->setupUi(this);


  qDebug() << "Qt Version:" << QT_VERSION_STR;
    // main application
    //QApplication app(argc, argv);

    // install signal handlers
    QObject::connect(this->ui->qBtnInit, &QPushButton::clicked,
      [&]() {
        if (pQGeoProvider) delete pQGeoProvider;
        std::ostringstream out;
        pQGeoProvider = init(out);
        log(out.str());
      });
    QObject::connect(this->ui->qBtnFind, &QPushButton::clicked,
      [&]() {
        // init geo coder if not yet done
        if (!pQGeoProvider) {
          std::ostringstream out;
          pQGeoProvider = init(out);
          log(out.str());
          if (!pQGeoProvider) return; // failed
        }
        // fill in request
        QGeoAddress *pQGeoAddr = new QGeoAddress;
        pQGeoAddr->setCountry(this->ui->qTxtCountry->text());
        pQGeoAddr->setPostalCode(this->ui->qTxtZipCode->text());
        pQGeoAddr->setCity(this->ui->qTxtCity->text());
        pQGeoAddr->setStreet(this->ui->qTxtStreet->text());
        QGeoCodeReply *pQGeoCode
          = pQGeoProvider->geocodingManager()->geocode(*pQGeoAddr);
        if (!pQGeoCode) {
          delete pQGeoAddr;
          log("GeoCoding totally failed!\n");
          return;
        }
        { std::ostringstream out;
          out << "Sending request for:\n"
            << pQGeoAddr->country().toUtf8().data() << "; "
            << pQGeoAddr->postalCode().toUtf8().data() << "; "
            << pQGeoAddr->city().toUtf8().data() << "; "
            << pQGeoAddr->street().toUtf8().data() << "...\n";
          log(out.str());
        }
        // install signal handler to process result later
        QObject::connect(pQGeoCode, &QGeoCodeReply::finished,
          [&,pQGeoAddr, pQGeoCode]() {
            // process reply
            std::ostringstream out;
            out << "Reply: " << pQGeoCode->errorString().toStdString() << '\n';
            switch (pQGeoCode->error()) {
              case QGeoCodeReply::NoError: {
                // eval result
                QList<QGeoLocation> qGeoLocs = pQGeoCode->locations();
                out << qGeoLocs.size() << " location(s) returned.\n";
                for (QGeoLocation &qGeoLoc : qGeoLocs) {
                  qGeoLoc.setAddress(*pQGeoAddr);
                  QGeoCoordinate qGeoCoord = qGeoLoc.coordinate();
                  out
                    << "Lat.:  " << qGeoCoord.latitude() << '\n'
                    << "Long.: " << qGeoCoord.longitude() << '\n'
                    << "Alt.:  " << qGeoCoord.altitude() << '\n';
                }
              } break;
  #define CASE(ERROR) \
  case QGeoCodeReply::ERROR: out << #ERROR << '\n'; break
              CASE(EngineNotSetError);
              CASE(CommunicationError);
              CASE(ParseError);
              CASE(UnsupportedOptionError);
              CASE(CombinationError);
              CASE(UnknownError);
  #undef CASE
              default: out << "Undocumented error!\n";
            }
            // log result
            log(out.str());
            // clean-up
            delete pQGeoAddr;
            /* delete sender in signal handler could be lethal
             * Hence, delete it later...
             */
            pQGeoCode->deleteLater();
          });
      });
    // fill in a sample request with a known address initially
    this->ui->qTxtCountry->setText(QString::fromUtf8("Germany"));
    this->ui->qTxtZipCode->setText(QString::fromUtf8("88250"));
    this->ui->qTxtCity->setText(QString::fromUtf8("Weingarten"));
    this->ui->qTxtStreet->setText(QString::fromUtf8("Danziger Str. 3"));


}

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


void MainWindow::log(const QString &qString)
{
  this->ui->qTxtLog->setPlainText(this->ui->qTxtLog->toPlainText() + qString);
  this->ui->qTxtLog->moveCursor(QTextCursor::End);
}
void MainWindow::log(const char *text)
{
  log(QString::fromUtf8(text));
}
void MainWindow::log(const std::string &text)
{
  log(text.c_str());
}

QGeoServiceProvider* MainWindow::init(std::ostream &out)
{
  // check for available services
  QStringList qGeoSrvList
    = QGeoServiceProvider::availableServiceProviders();
  for (QString entry : qGeoSrvList) {
    out << "Try service: " << entry.toStdString() << '\n';
    // choose provider
    QGeoServiceProvider *pQGeoProvider = new QGeoServiceProvider(entry);
    if (!pQGeoProvider) {
      out
        << "ERROR: GeoServiceProvider '" << entry.toStdString()
        << "' not available!\n";
      continue;
    }
    QGeoCodingManager *pQGeoCoder = pQGeoProvider->geocodingManager();
    if (!pQGeoCoder) {
      out
        << "ERROR: GeoCodingManager '" << entry.toStdString()
        << "' not available!\n";
      delete pQGeoProvider;
      continue;
    }
    QLocale qLocaleC(QLocale::C, QLocale::AnyCountry);
    pQGeoCoder->setLocale(qLocaleC);
    out << "Using service " << entry.toStdString() << '\n';
    return pQGeoProvider; // success
  }
  out << "ERROR: No suitable GeoServiceProvider found!\n";
  return nullptr; // all attempts failed
}

main.cpp:

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
  QApplication a(argc, argv);
  MainWindow w;
  w.show();

  return a.exec();
}

这里是主窗口的头文件:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
// standard C++ header:
#include <iostream>
#include <sstream>

// Qt header:

#include <QGeoAddress>
#include <QGeoCodingManager>
#include <QGeoCoordinate>
#include <QGeoLocation>
#include <QGeoServiceProvider>
namespace Ui {
  class MainWindow;
}

class MainWindow : public QMainWindow
{
  Q_OBJECT

public:
  explicit MainWindow(QWidget *parent = 0);
  virtual ~MainWindow();


  void log(const QString &qString);

  void log(const char *text);

  void log(const std::string &text);


  QGeoServiceProvider* init(std::ostream &out);

private:
  Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

最佳答案

我改造了my older sample到带有 GUI 的最小应用程序:

// standard C++ header:
#include <iostream>
#include <sstream>

// Qt header:
#include <QtWidgets>
#include <QGeoAddress>
#include <QGeoCodingManager>
#include <QGeoCoordinate>
#include <QGeoLocation>
#include <QGeoServiceProvider>

void log(QTextEdit &qTxtLog, const QString &qString)
{
  qTxtLog.setPlainText(qTxtLog.toPlainText() + qString);
  qTxtLog.moveCursor(QTextCursor::End);
}
void log(QTextEdit &qTxtLog, const char *text)
{
  log(qTxtLog, QString::fromUtf8(text));
}
void log(QTextEdit &qTxtLog, const std::string &text)
{
  log(qTxtLog, text.c_str());
}

int main(int argc, char **argv)
{
  qDebug() << "Qt Version:" << QT_VERSION_STR;
  // main application
  QApplication app(argc, argv);
  // setup GUI
  QWidget qWin;
  QVBoxLayout qBox;
  QFormLayout qForm;
  QLabel qLblCountry(QString::fromUtf8("Country:"));
  QLineEdit qTxtCountry;
  qForm.addRow(&qLblCountry, &qTxtCountry);
  QLabel qLblZipCode(QString::fromUtf8("Postal Code:"));
  QLineEdit qTxtZipCode;
  qForm.addRow(&qLblZipCode, &qTxtZipCode);
  QLabel qLblCity(QString::fromUtf8("City:"));
  QLineEdit qTxtCity;
  qForm.addRow(&qLblCity, &qTxtCity);
  QLabel qLblStreet(QString::fromUtf8("Street:"));
  QLineEdit qTxtStreet;
  qForm.addRow(&qLblStreet, &qTxtStreet);
  QLabel qLblProvider(QString::fromUtf8("Provider:"));
  QComboBox qLstProviders;
  qForm.addRow(&qLblProvider, &qLstProviders);
  qBox.addLayout(&qForm);
  QPushButton qBtnFind(QString::fromUtf8("Find Coordinates"));
  qBox.addWidget(&qBtnFind);
  QLabel qLblLog(QString::fromUtf8("Log:"));
  qBox.addWidget(&qLblLog);
  QTextEdit qTxtLog;
  qTxtLog.setReadOnly(true);
  qBox.addWidget(&qTxtLog);
  qWin.setLayout(&qBox);
  qWin.show();
  // initialize Geo Service Providers
  std::vector<QGeoServiceProvider*> pQGeoProviders;
  { std::ostringstream out;
    QStringList qGeoSrvList
      = QGeoServiceProvider::availableServiceProviders();
    for (QString entry : qGeoSrvList) {
      out << "Try service: " << entry.toStdString() << '\n';
      // choose provider
      QGeoServiceProvider *pQGeoProvider = new QGeoServiceProvider(entry);
      if (!pQGeoProvider) {
        out
          << "ERROR: GeoServiceProvider '" << entry.toStdString()
          << "' not available!\n";
        continue;
      }
      QGeoCodingManager *pQGeoCoder = pQGeoProvider->geocodingManager();
      if (!pQGeoCoder) {
        out
          << "ERROR: GeoCodingManager '" << entry.toStdString()
          << "' not available!\n";
        delete pQGeoProvider;
        continue;
      }
      QLocale qLocaleC(QLocale::C, QLocale::AnyCountry);
      pQGeoCoder->setLocale(qLocaleC);
      qLstProviders.addItem(entry);
      pQGeoProviders.push_back(pQGeoProvider);
      out << "Service " << entry.toStdString() << " available.\n";
    }
    log(qTxtLog, out.str());
  }
  if (pQGeoProviders.empty()) qBtnFind.setEnabled(false);
  // install signal handlers
  QObject::connect(&qBtnFind, QPushButton::clicked,
    [&]() {
      // get current geo service provider
      QGeoServiceProvider *pQGeoProvider
        = pQGeoProviders[qLstProviders.currentIndex()];
      // fill in request
      QGeoAddress *pQGeoAddr = new QGeoAddress;
      pQGeoAddr->setCountry(qTxtCountry.text());
      pQGeoAddr->setPostalCode(qTxtZipCode.text());
      pQGeoAddr->setCity(qTxtCity.text());
      pQGeoAddr->setStreet(qTxtStreet.text());
      QGeoCodeReply *pQGeoCode
        = pQGeoProvider->geocodingManager()->geocode(*pQGeoAddr);
      if (!pQGeoCode) {
        delete pQGeoAddr;
        log(qTxtLog, "GeoCoding totally failed!\n");
        return;
      }
      { std::ostringstream out;
        out << "Sending request for:\n"
          << pQGeoAddr->country().toUtf8().data() << "; "
          << pQGeoAddr->postalCode().toUtf8().data() << "; "
          << pQGeoAddr->city().toUtf8().data() << "; "
          << pQGeoAddr->street().toUtf8().data() << "...\n";
        log(qTxtLog, out.str());
      }
      // install signal handler to process result later
      QObject::connect(pQGeoCode, &QGeoCodeReply::finished,
        [&qTxtLog, pQGeoAddr, pQGeoCode]() {
          // process reply
          std::ostringstream out;
          out << "Reply: " << pQGeoCode->errorString().toStdString() << '\n';
          switch (pQGeoCode->error()) {
            case QGeoCodeReply::NoError: {
              // eval result
              QList<QGeoLocation> qGeoLocs = pQGeoCode->locations();
              out << qGeoLocs.size() << " location(s) returned.\n";
              for (QGeoLocation &qGeoLoc : qGeoLocs) {
                qGeoLoc.setAddress(*pQGeoAddr);
                QGeoCoordinate qGeoCoord = qGeoLoc.coordinate();
                out
                  << "Lat.:  " << qGeoCoord.latitude() << '\n'
                  << "Long.: " << qGeoCoord.longitude() << '\n'
                  << "Alt.:  " << qGeoCoord.altitude() << '\n';
              }     
            } break;
#define CASE(ERROR) \
            case QGeoCodeReply::ERROR: out << #ERROR << '\n'; break
            CASE(EngineNotSetError);
            CASE(CommunicationError);
            CASE(ParseError);
            CASE(UnsupportedOptionError);
            CASE(CombinationError);
            CASE(UnknownError);
#undef CASE
            default: out << "Undocumented error!\n";
          }
          // log result
          log(qTxtLog, out.str());
          // clean-up
          delete pQGeoAddr;
          /* delete sender in signal handler could be lethal
           * Hence, delete it later...
           */
          pQGeoCode->deleteLater();
        });
    });
  // fill in a sample request with a known address initially
  qTxtCountry.setText(QString::fromUtf8("Germany"));
  qTxtZipCode.setText(QString::fromUtf8("88250"));
  qTxtCity.setText(QString::fromUtf8("Weingarten"));
  qTxtStreet.setText(QString::fromUtf8("Danziger Str. 3"));
  // runtime loop
  app.exec();
  // done
  return 0;
}

cygwin 中编译和测试在 Windows 10(64 位)上:

$ g++ --version
g++ (GCC) 6.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ qmake-qt5 testQGeoAddressGUI.pro

$ make
g++ -c -fno-keep-inline-dllexport -D_GNU_SOURCE -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_LOCATION_LIB -DQT_QUICK_LIB -DQT_GUI_LIB -DQT_POSITIONING_LIB -DQT_QML_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -I. -isystem /usr/include/qt5 -isystem /usr/include/qt5/QtWidgets -isystem /usr/include/qt5/QtLocation -isystem /usr/include/qt5/QtQuick -isystem /usr/include/qt5/QtGui -isystem /usr/include/qt5/QtPositioning -isystem /usr/include/qt5/QtQml -isystem /usr/include/qt5/QtNetwork -isystem /usr/include/qt5/QtCore -I. -I/usr/lib/qt5/mkspecs/cygwin-g++ -o testQGeoAddressGUI.o testQGeoAddressGUI.cc
g++  -o testQGeoAddressGUI.exe testQGeoAddressGUI.o   -lQt5Widgets -lQt5Location -lQt5Quick -lQt5Gui -lQt5Positioning -lQt5Qml -lQt5Network -lQt5Core -lGL -lpthread 

$ ./testQGeoAddressGUI
Qt Version: 5.9.2

Snapshot of testQGeoAddressGUI

注意事项:

当我编写这个示例时,我非常注意所涉及变量的范围和生命周期。 (实际上,我将一些局部变量更改为使用 new 创建的指针和实例来实现此目的。)这是我对所有读者的提示。

在我的 1st 测试中,应用程序以 CommunicationError 结束。我很确定我们公司的安全政策对此负责。 (我对我在家里成功测试的旧 sample 做了同样的事情——结果相同。)

第二次nd 测试(在家)进行得更好。首先,我试图找到服务提供商 osm 的地址,但结果为 0。将服务提供商更改为 esri 返回了一个结果。

我将输出复制到 maps.google.de:

Snapshot of maps.google.de after request of 47.8187, 9.64387

这实际上是正确的结果——因为我测试了公司的(新)地址 EKS InTec我工作的地方。


在上面的例子中使用了 lambdas 使得它有点难以阅读。因此,我重新访问了样本。现在,所有相关内容都已移至 class MainWindow(希望更接近 OP 的要求)。 lambdas 被简单的方法所取代。

// standard C++ header:
#include <iostream>
#include <sstream>

// Qt header:
#include <QtWidgets>
#include <QGeoAddress>
#include <QGeoCodingManager>
#include <QGeoCoordinate>
#include <QGeoLocation>
#include <QGeoServiceProvider>

// main window class
class MainWindow: public QWidget {
  // variables:
  private:
    // list of service providers
    std::vector<QGeoServiceProvider*> pQGeoProviders;
    // Qt widgets (contents of main window)
    QVBoxLayout qBox;
    QFormLayout qForm;
    QLabel qLblCountry;
    QLineEdit qTxtCountry;
    QLabel qLblZipCode;
    QLineEdit qTxtZipCode;
    QLabel qLblCity;
    QLineEdit qTxtCity;
    QLabel qLblStreet;
    QLineEdit qTxtStreet;
    QLabel qLblProvider;
    QComboBox qLstProviders;
    QPushButton qBtnFind;
    QLabel qLblLog;
    QTextEdit qTxtLog;

  // methods:
  public: // ctor/dtor
    MainWindow(QWidget *pQParent = nullptr);
    virtual ~MainWindow();
    MainWindow(const MainWindow&) = delete;
    MainWindow& operator=(const MainWindow&) = delete;

  private: // internal stuff
    void init(); // initializes geo service providers
    void find(); // sends request
    void report(); // processes reply
    void log(const QString &qString)
    {
      qTxtLog.setPlainText(qTxtLog.toPlainText() + qString);
      qTxtLog.moveCursor(QTextCursor::End);
    }
    void log(const char *text) { log(QString::fromUtf8(text)); }
    void log(const std::string &text) { log(text.c_str()); }
};

MainWindow::MainWindow(QWidget *pQParent):
  QWidget(pQParent),
  qLblCountry(QString::fromUtf8("Country:")),
  qLblZipCode(QString::fromUtf8("Postal Code:")),
  qLblCity(QString::fromUtf8("City:")),
  qLblStreet(QString::fromUtf8("Street:")),
  qLblProvider(QString::fromUtf8("Provider:")),
  qBtnFind(QString::fromUtf8("Find Coordinates")),
  qLblLog(QString::fromUtf8("Log:"))
{
  // setup child widgets
  qForm.addRow(&qLblCountry, &qTxtCountry);
  qForm.addRow(&qLblZipCode, &qTxtZipCode);
  qForm.addRow(&qLblCity, &qTxtCity);
  qForm.addRow(&qLblStreet, &qTxtStreet);
  qForm.addRow(&qLblProvider, &qLstProviders);
  qBox.addLayout(&qForm);
  qBox.addWidget(&qBtnFind);
  qBox.addWidget(&qLblLog);
  qBox.addWidget(&qTxtLog);
  setLayout(&qBox);
  // init service provider list
  init();
  // install signal handlers
  QObject::connect(&qBtnFind, &QPushButton::clicked,
    this, &MainWindow::find);
  // fill in a sample request with a known address initially
  qTxtCountry.setText(QString::fromUtf8("Germany"));
  qTxtZipCode.setText(QString::fromUtf8("88250"));
  qTxtCity.setText(QString::fromUtf8("Weingarten"));
  qTxtStreet.setText(QString::fromUtf8("Danziger Str. 3"));
}

MainWindow::~MainWindow()
{
  // clean-up
  for (QGeoServiceProvider *pQGeoProvider : pQGeoProviders) {
    delete pQGeoProvider;
  }
}

void MainWindow::init()
{
  // initialize Geo Service Providers
  { std::ostringstream out;
    QStringList qGeoSrvList
      = QGeoServiceProvider::availableServiceProviders();
    for (QString entry : qGeoSrvList) {
      out << "Try service: " << entry.toStdString() << '\n';
      // choose provider
      QGeoServiceProvider *pQGeoProvider = new QGeoServiceProvider(entry);
      if (!pQGeoProvider) {
        out
          << "ERROR: GeoServiceProvider '" << entry.toStdString()
          << "' not available!\n";
        continue;
      }
      QGeoCodingManager *pQGeoCoder = pQGeoProvider->geocodingManager();
      if (!pQGeoCoder) {
        out
          << "ERROR: GeoCodingManager '" << entry.toStdString()
          << "' not available!\n";
        delete pQGeoProvider;
        continue;
      }
      QLocale qLocaleC(QLocale::C, QLocale::AnyCountry);
      pQGeoCoder->setLocale(qLocaleC);
      qLstProviders.addItem(entry);
      pQGeoProviders.push_back(pQGeoProvider);
      out << "Service " << entry.toStdString() << " available.\n";
    }
    log(out.str());
  }
  if (pQGeoProviders.empty()) qBtnFind.setEnabled(false);
}

std::string format(const QGeoAddress &qGeoAddr)
{
  std::ostringstream out;
  out
    << qGeoAddr.country().toUtf8().data() << "; "
    << qGeoAddr.postalCode().toUtf8().data() << "; "
    << qGeoAddr.city().toUtf8().data() << "; "
    << qGeoAddr.street().toUtf8().data();
  return out.str();
}

void MainWindow::find()
{
  // get current geo service provider
  QGeoServiceProvider *pQGeoProvider
    = pQGeoProviders[qLstProviders.currentIndex()];
  // fill in request
  QGeoAddress qGeoAddr;
  qGeoAddr.setCountry(qTxtCountry.text());
  qGeoAddr.setPostalCode(qTxtZipCode.text());
  qGeoAddr.setCity(qTxtCity.text());
  qGeoAddr.setStreet(qTxtStreet.text());
  QGeoCodeReply *pQGeoCode
    = pQGeoProvider->geocodingManager()->geocode(qGeoAddr);
  if (!pQGeoCode) {
    log("GeoCoding totally failed!\n");
    return;
  }
  { std::ostringstream out;
    out << "Sending request for:\n"
      << format(qGeoAddr) << "...\n";
    log(out.str());
  }
  // install signal handler to process result later
  QObject::connect(pQGeoCode, &QGeoCodeReply::finished,
    this, &MainWindow::report);
  /* This signal handler will delete it's own sender.
   * Hence, the connection need not to be remembered
   * although it has only a limited life-time.
   */
}

void MainWindow::report()
{
  QGeoCodeReply *pQGeoCode
    = dynamic_cast<QGeoCodeReply*>(sender());
  // process reply
  std::ostringstream out;
  out << "Reply: " << pQGeoCode->errorString().toStdString() << '\n';
  switch (pQGeoCode->error()) {
    case QGeoCodeReply::NoError: {
      // eval result
      QList<QGeoLocation> qGeoLocs = pQGeoCode->locations();
      out << qGeoLocs.size() << " location(s) returned.\n";
      for (QGeoLocation &qGeoLoc : qGeoLocs) {
        QGeoAddress qGeoAddr = qGeoLoc.address();
        QGeoCoordinate qGeoCoord = qGeoLoc.coordinate();
        out
          << "Coordinates for "
          << qGeoAddr.text().toUtf8().data() << ":\n"
          << "Lat.:  " << qGeoCoord.latitude() << '\n'
          << "Long.: " << qGeoCoord.longitude() << '\n'
          << "Alt.:  " << qGeoCoord.altitude() << '\n';
      }     
    } break;
#define CASE(ERROR) \
case QGeoCodeReply::ERROR: out << #ERROR << '\n'; break
    CASE(EngineNotSetError);
    CASE(CommunicationError);
    CASE(ParseError);
    CASE(UnsupportedOptionError);
    CASE(CombinationError);
    CASE(UnknownError);
#undef CASE
    default: out << "Undocumented error!\n";
  }
  // log result
  log(out.str());
  // clean-up
  /* delete sender in signal handler could be lethal
   * Hence, delete it later...
   */
  pQGeoCode->deleteLater();
}

int main(int argc, char **argv)
{
  qDebug() << "Qt Version:" << QT_VERSION_STR;
  // main application
  QApplication app(argc, argv);
  // setup GUI
  MainWindow win;
  win.show();
  // runtime loop
  app.exec();
  // done
  return 0;
}

注意:

外观和行为与上述示例相同。我稍微更改了回复的输出。

在准备这个示例时,我意识到实际上没有必要设置返回的 QGeoLocation 的地址,因为它已经存在了。恕我直言,有趣的是返回的地址看起来与请求的地址有点不同。它似乎以(我会说)规范化形式返回。

关于c++ - 如何使用 Qt c++ QGeoServiceProvider 从地理地址获取纬度/经度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50344495/

相关文章:

c++ - 派生类中的constexpression,clang vs rest

C++:如何检查我的窗口是否即将关闭?

c++ - QML map 可见区域

c++ - CMake看不到系统变量

c++ - Qt 获取文本更改

python - 使用 Python 将空文件夹附加到 KML 文件中的现有文件夹

google-maps - 谷歌地图 - 如何从地址获取建筑物的多边形坐标?

Java 泛型和 C++ 模板,如果生成的代码大小很重要,哪个是首选?

c++ - 取消连接是 boost::asio

google-maps - Google map - 对许多地址进行预地理编码?