qt6 获取百度地图(一)

需求分析:

要获取一个地图,

需要ip

需要根据ip查询经纬度

根据经纬度查询地图

另外一条线是根据输入的地址 查询ip 根据查询到的ip查地图‘

最后,要渲染地图

上面这这些动作,要进行http查询:

为此要有三个QNetworkAccessManager对象:

    QNetworkAccessManager *m_ipManager;  // 用于ip管理
    QNetworkAccessManager *m_locManager;   // 用于查询位置
    //网络管理对象  发送地图图片
    QNetworkAccessManager *m_mapManager;   //查询地图
    //响应对象 接收地图图片
    QNetworkReply *m_mapReply=NULL;   //响应

所有的查询动作当然能顺序执行:

如先查询ip

    等待获取IP返回结果

         如果IP返回了,发起根据IP查询经纬度的请求

                等待经纬度查询结果,如果获得的返回,则进一步根据返回的经纬度查询地图数据

                         等待地图数据查询结果,把结果写入文件

                                  从文件中读取数据,渲染到weigt上

但是 如果其中某个环节网络断了 或者百度服务器宕机了,系统就会卡死。

按上面步骤,网络请求是同步顺序,执行来的,用户界面可能会阻塞,用户体验欠佳。

为此我们引入槽函数机制!让网络请求是异步进行,用户界面不会阻塞,这提供了更好的用户体验!

在构造函数中,添加如下代码:

Form1::Form1(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Form1)
{
    ui->setupUi(this);
    //new一个网络管理对象
    m_ipManager = new QNetworkAccessManager(this);  //  net connection tool ,duty is to connect to the server
    //declare  connect relationship ,when receive the response ,call the slot function,response is finished signal
    connect(m_ipManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onGetIp(QNetworkReply*)));

    m_locManager=new QNetworkAccessManager(this);  //net connection tool ,duty is to connect to the server for location
    //declare  connect relationship ,when receive the response ,call the slot function,response is finished signal
    connect(m_locManager,SIGNAL(finished(QNetworkReply*)),this,SLOT(onGetCurrentLoc(QNetworkReply*)));

    m_mapManager=new QNetworkAccessManager(this);   //net connection tool ,duty is to connect to the server for map query map
    connect(m_mapManager,SIGNAL(finished(QNetworkReply*)),this,SLOT(onSendMapRequest()));
}

和上面connect函数配套的也有三个槽函数,当网络请求有响应的时候,执行响应的槽函数。

配套的三个槽函数,在头文件中 declare如下图:

private slots:
  

    //处理获取外网ip请求的 槽
    void onGetIp(QNetworkReply*);
    //根据ip获取经纬度  处理服务器响应内容
    void onGetCurrentLoc(QNetworkReply*);
    //处理服务器返回地图图片
    void onSendMapRequest();

这样,所有网络查询与处理事异步进行的。

让我们从查询Ip地址起步:

首先通过QNetworkAccessManager 一个实例对象 m_ipManager发起一个request请求。

void Form1::getIp()
{
  // by m_ipManager query ip
    QUrl url("http://httpbin.org/ip");  //declare the url
    QNetworkRequest request(url);  //declare the request
    m_ipManager->get(request);   //send the request
}

这个请求的响应?

嗯嗯,当然在槽函数当中了~~~ 窗体的构造函数中不是“声明”了一个“连接”吗

 connect(m_ipManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onGetIp(QNetworkReply*)));

当网络请求有相应的回来的时候,执行槽函数onGetIp,

在这个onGetIp函数中,我们取得服务端返回数据,从中解析出ip地址,进一步的, 我们会根据ip地址查询经纬度数据。

void Form1::onGetIp(QNetworkReply *reply)
{
    //get the ip address,by ip value query the location
    QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll());
    QJsonObject jsonObj = jsonDoc.object();
    currentIp=jsonObj.value("origin").toString();
    qDebug() << "Current IP:" << currentIp;
    //by ip value query the location
    getLocation();

}

void Form1::getLocation()
{
    //by ip address ,query the location
    QUrl url("http://api.map.baidu.com/location/ip?ip="+currentIp+"&ak="+ak);
    QNetworkRequest request(url);
    m_locManager->get(request);
}

上面查询经纬度数据的时候,用的是QNetworkAccessManager 一个实例对象 m_locManager,当这个对象发起request请求后,它的工作就算完成了。

结果?结果当然是另外一个槽函数来处理了。

connect(m_locManager,SIGNAL(finished(QNetworkReply*)),this,SLOT(onGetCurrentLoc(QNetworkReply*)));

 onGetCurrentLoc这个槽函数中,获取上一步request查询结果,从结果中解析出经纬度,根据经纬度的数据,调用查询地图数据的函数。

完整代码如下:

//json数据的一个样本如下
// {
//     "address": "CN|辽宁省|大连市|None|None|100|75",
//     "content": {
//         "address_detail": {
//             "province": "辽宁省",
//             "city": "大连市",
//             "district": "",
//             "street": "",
//             "street_number": "",
//             "city_code": 167,
//             "adcode": "210200"
//         },
//         "address": "辽宁省大连市",
//         "point": {
//             "x": "13539005.4",
//             "y": "4682974.61"
//         }
//     },
//     "status": 0
// }

void Form1::onGetCurrentLoc(QNetworkReply * reply)
{
    //根据经纬度发起查询地图
    QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll());


    //parse the json data,get the location data from the json data
    QJsonObject jsonObj = jsonDoc.object();
    QJsonObject contentObj = jsonObj.value("content").toObject();
    QJsonObject pointObj = contentObj.value("point").toObject();
    m_lng = pointObj.value("x").toString().toDouble();
    m_lat = pointObj.value("y").toString().toDouble();
    qDebug() << "经度:" << m_lng << "纬度:" << m_lat;
    //根据经纬度发起查询地图请求
    //发起查询地图请求
    sendMapRequest();

}

到这一步,我们可以先测试一下:~~~~~~~~~~~~

看上去一切正常!其实是有问题的。

其中,sendMapRequest,当然是用一个对象发起一个请求,结果同样是在对应的槽函数当中处理

sendMapRequest完整代码如下:

void Form1::sendMapRequest()
{
    //by location query the map, use  m_mapManager
    QString url="http://api.map.baidu.com/staticimage/v2?ak="+ak+"&center="+QString::number(m_lng)+","+QString::number(m_lat)+"&width=1024&height=768&zoom="+QString::number(m_zoom);
    QNetworkRequest request(url);
    m_mapManager->get(request);
}

好了吗?且慢,网络查询获取的地图数据,也只能是应答对象reply,给出完成型号的时候,才能进行,就是说,构造函数中 connect(m_mapManager,SIGNAL(finished(QNetworkReply*)),this,SLOT(onSendMapRequest()));  不是很合适,那就改造它,

构造函数相关代码改造为:

Form1::Form1(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Form1)
{
    ui->setupUi(this);
    //new一个网络管理对象
    m_ipManager = new QNetworkAccessManager(this);  //  net connection tool ,duty is to connect to the server
    //declare  connect relationship ,when receive the response ,call the slot function,response is finished signal
    connect(m_ipManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onGetIp(QNetworkReply*)));

    m_locManager=new QNetworkAccessManager(this);  //net connection tool ,duty is to connect to the server for location
    //declare  connect relationship ,when receive the response ,call the slot function,response is finished signal
    connect(m_locManager,SIGNAL(finished(QNetworkReply*)),this,SLOT(onGetCurrentLoc(QNetworkReply*)));

    m_mapManager=new QNetworkAccessManager(this);  
 //注释掉下面的行  只有收到reply发出的准备好信号 我们才能读取数据,保存到文件当中
   // connect(m_mapManager,SIGNAL(finished(QNetworkReply*)),this,SLOT(onSendMapRequest()));
}

只有reply发出准备好可以读数据的信号后,才能,触发对应的槽函数:由于读取文件数据是个昂贵的资源,所以我们要

 void  MainWindow::sendMapRequest(){
     //how

     //断调前一次请求
     if(m_mapReply!=NULL){
         m_mapReply->disconnect();
         //断掉事件连接
         disconnect(m_mapReply,&QIODevice::readyRead,this,&MainWindow::onSendMapRequest);
     }

     //开始新的请求
     //url
     //请求地址
     QString host= "http://api.map.baidu.com/staticimage/v2";
     //请求参数
     QString query_str=QString("ak=%1&width=512&height=256&center=%2,%3&zoom=%4")
             .arg(ak).arg(m_lng).arg(m_lat).arg(m_zoom);
     QUrl url(host+"?"+query_str);

     qDebug()<<host+"?"+query_str<<endl;

     QNetworkRequest request(url);
     //此处与前面的请求不同,等待服务器响应,
     m_mapReply= m_mapManager->get(request);
     //连接事件,处理服务器返回的 文件流
     connect(m_mapReply,&QIODevice::readyRead,this,&MainWindow::onSendMapRequest);
 }

获取地图数据是个相对比较昂贵的操作,假如原来有个正在处理的响应呢,当然应该断掉原来的响应啊。所有有了下面的代码:

     //断调前一次请求
     if(m_mapReply!=NULL){
         m_mapReply->disconnect();
         //断掉事件连接
         disconnect(m_mapReply,&QIODevice::readyRead,this,&MainWindow::onSendMapRequest);
     }

回顾上面的代码sendMapRequest中执行的动作为:

断开原有的http连接

断开reply相关的槽函数链接

通过http发起查询地图的连接

建了信号与槽函数间的联系,通过槽函数,处理数据,。

最后一步:如何把读取到的数据存放到文件中,且渲染到weight当中呢?

且听下回分解,明天见!

ps:   测试根据ip查询经纬度的数据:http://api.map.baidu.com/location/ip?ip=42.84.232.111&ak=***********

ps:

http://api.map.baidu.com/staticimage/v2?ak=********&width=512&height=256&center=121.622,38.919&zoom=12

该URL是百度地图静态图片API的一个请求示例,用于生成指定位置、尺寸和缩放级别的地图图片。下面是对各个参数的详细解释:

  1. http://api.map.baidu.com/staticimage/v2:
    • 这是百度地图静态图片API的基础URL,用于访问静态地图服务。v2表示API的版本号,不同版本可能支持不同的功能和参数。
  2. ak=********
    • ak(Access Key)是访问百度地图API时必需的认证密钥。每个开发者在百度地图开放平台注册并创建应用后,会获得一个唯一的AK,用于API请求的认证。这里的yYSnHDIgAbSRlyktehYXmvlzA0s3eEhX是一个示例密钥,实际使用时需要替换成自己的AK。
  3. width=512:
    • width参数指定了生成图片的宽度,单位为像素。在这个例子中,图片的宽度被设置为512像素。
  4. height=256:
    • height参数指定了生成图片的高度,单位为像素。在这个例子中,图片的高度被设置为256像素。
  5. center=121.622,38.919:
    • center参数用于指定地图的中心点坐标。这里使用经纬度表示,经度为121.622,纬度为38.919。这个坐标点大致位于中国的某个位置(具体位置取决于经纬度值)。
  6. zoom=12:
    • zoom参数用于指定地图的缩放级别。缩放级别越高,地图显示的内容越详细。百度地图的缩放级别范围通常是3到19,其中3表示世界概览,而更高的数字则表示更详细的地区视图。在这个例子中,缩放级别被设置为12,表示地图将展示较为详细的区域信息。

综上所述,这个URL请求百度地图静态图片API生成一个宽度为512像素、高度为256像素的地图图片,图片的中心点位于经度121.622、纬度38.919的位置,且地图的缩放级别为12。通过修改这些参数,可以生成不同尺寸、不同位置和不同缩放级别的地图图片。

ps:问题1:qt6 处理图像的基本步骤:

在Qt6中处理图像的基本步骤通常涉及以下几个关键方面,以及所使用的核心工具类。以下是一个简要的描述:

基本步骤

  1. 创建图像对象
    首先,需要创建一个QImageQPixmap对象来存储或处理图像。QImage是一个类,用于处理图像数据,支持多种图像格式和色彩深度,包括灰度图像、彩色图像和索引图像。它提供了丰富的图像处理功能,如读取、写入、转换图像格式等。

  2. 读取图像数据
    使用QImageload()函数从文件、数据流或其他源中读取图像数据。这个函数支持多种图像格式,如PNG、JPEG、BMP等。

  3. 处理图像
    通过QImage提供的各种函数对图像进行处理,如缩放、裁剪、旋转、颜色转换等。Qt6还提供了更高级的图像处理功能,如滤镜效果、图像分析等,这些功能可能通过其他类库(如Qt Image Processing模块)实现。

  4. 显示图像
    将处理后的图像显示在界面上,通常可以通过将QImage转换为QPixmap(如果需要的话),然后使用QLabelQGraphicsView等控件进行显示。

  5. 保存图像
    如果需要,可以将处理后的图像保存回文件或其他存储介质。使用QImagesave()函数可以实现这一功能。

用到的工具类

  • QImage:用于处理图像数据,包括读取、写入、转换格式和进行基本的图像处理。
  • QPixmap:与QImage类似,但优化了图像在屏幕上的显示性能。通常用于将图像显示在GUI控件中。
  • QPainter:虽然主要用于绘图,但在图像处理过程中也可以用来在图像上绘制图形或文本,实现更复杂的图像处理效果。
  • 其他Qt图像处理模块:Qt可能还提供了其他专门的图像处理模块,如Qt Image Processing,这些模块提供了更高级的图像处理功能。

综上所述,Qt6处理图像的基本步骤包括创建图像对象、读取图像数据、处理图像、显示图像和保存图像,而用到的核心工具类主要是QImageQPixmap,辅以QPainter和其他可能的Qt图像处理模块。

问题2:qt6 用QPainter绘制图像有哪些功能,具体步骤是什么

在Qt6中,QPainter是用于在各种绘制设备(如窗口、图片等)上进行绘图的强大工具类。使用QPainter绘制图像时,它提供了丰富的功能,包括但不限于:

  1. 基本图形绘制:可以绘制点、线、矩形、圆形、椭圆等基本图形,以及更复杂的形状如多边形、扇形等。

  2. 文本绘制:支持绘制文本,并可以设置文本的字体、颜色、位置等属性。

  3. 图像绘制:可以直接在绘图设备上绘制图像(如QImageQPixmap中的图像)。

  4. 变换:支持坐标变换,如平移、旋转、缩放等,以实现对图形的变换处理。

具体步骤通常包括:

  1. 创建QPainter对象:在绘图事件处理函数(如paintEvent)中创建QPainter对象,并指定绘图设备(如this指针,表示在当前窗口上绘图)。

  2. 设置绘制属性:根据需要设置画笔(QPen)、画刷(QBrush)、字体(QFont)等属性。

  3. 进行绘图操作:使用QPainter提供的绘图函数进行绘图,如drawLinedrawRectdrawText等。

  4. 结束绘图:绘图完成后,QPainter对象会自动销毁,或者可以显式调用其end()方法来结束绘图操作(尽管在自动管理的上下文中通常不需要)。

通过这些步骤,开发者可以在Qt6应用程序中实现丰富的图形绘制功能。

问题3:QPainter 与 QImage QPixmap 的关系是什么

QPainter、QImage和QPixmap在Qt框架中各自扮演着重要的角色,并且它们之间存在着紧密的关系。以下是对这三者之间关系的详细阐述:

1. QPainter

  • 功能:QPainter是Qt中用于在绘图设备上进行绘图的类。它提供了丰富的绘图函数,如绘制线条、形状、文本以及图像等。
  • 与QImage和QPixmap的关系:QPainter可以作用于QImage和QPixmap上,进行图像的绘制和编辑。这意味着,你可以使用QPainter在QImage或QPixmap对象上绘制图形、文本或其他图像。

2. QImage

  • 功能:QImage是Qt中用于处理图像数据的类。它提供了对图像像素的直接访问,允许进行图像的读取、写入、转换以及像素级别的操作。
  • 与QPainter的关系:QImage是QPaintDevice的子类,因此QPainter可以直接在其上进行绘制。这使得QImage成为一个非常灵活的绘图表面,可以在其上绘制图形、文本或其他图像。
  • 特点:QImage不依赖于底层硬件,提供了独立于平台的图像处理能力。它支持多种图像格式和色彩深度,并允许在多个线程中进行图像的读取和写入操作。

3. QPixmap

  • 功能:QPixmap是Qt中专门用于在屏幕上显示图像优化的类。它针对屏幕显示进行了优化,能够提供更好的性能和显示效果。
  • 与QPainter的关系:与QImage类似,QPixmap也是QPaintDevice的子类,因此QPainter同样可以在其上进行绘制。但是,由于QPixmap是为屏幕显示而优化的,因此它更适合在GUI应用程序中使用。
  • 特点:QPixmap依赖于底层平台的绘制系统,因此在不同的操作系统上可能会有不同的显示效果。此外,由于它针对屏幕显示进行了优化,因此在处理大型图像或进行复杂图像处理时可能会比QImage慢。

4. 关系总结

  • 绘图功能:QPainter是绘图工具,可以在QImage和QPixmap上进行绘图操作。
  • 图像数据:QImage和QPixmap都是用于处理图像数据的类,但它们的用途和优化方向有所不同。QImage提供了像素级别的访问和操作,而QPixmap则优化了屏幕显示性能。
  • 相互转换:QImage和QPixmap之间可以进行相互转换。可以使用QPixmap的toImage()函数将其转换为QImage,或者使用QImage的QPixmap::fromImage()静态函数将其转换为QPixmap。这种转换使得开发者可以根据需要选择最适合当前任务的图像处理类。

综上所述,QPainter、QImage和QPixmap在Qt中共同构成了强大的图像处理和绘图功能体系。它们之间的关系使得开发者可以灵活地选择和使用这些类来满足不同的图像处理和绘图需求。

问题4:不是可以这样比喻 qt6中 QPainter 是画家,QPixmap 是画布 QPen 是画笔 QPainter 这个画家可以使用QPen 这个画笔 在 QPixmap 这个画布上绘制图形

这个比喻非常贴切且易于理解!在Qt6的上下文中,我们可以这样描述这三个类之间的关系:

  • QPainter 确实是“画家”,它负责执行绘制操作,将图形、文本或其他图像绘制到指定的绘图设备(如窗口、图像等)上。QPainter提供了丰富的绘图函数,使得开发者可以像画家一样在绘图设备上进行创作。

  • QPixmap 可以被看作是“画布”,它是专门为屏幕显示而优化的图像表示。QPixmap对象可以作为QPainter的绘图设备,让QPainter在其上进行绘制。就像画家在画布上作画一样,QPainter可以在QPixmap上绘制各种图形和图像。

  • QPen 则是“画笔”,它定义了绘制线条时的样式,包括颜色、宽度、线型(如实线、虚线等)和线帽样式等。通过设置QPen的属性,开发者可以控制QPainter绘制线条时的外观。虽然QPen主要用于绘制线条,但它也间接影响了其他需要线条的图形(如矩形边框、圆形轮廓等)的绘制效果。

因此,你的比喻“QPainter 是画家,QPixmap 是画布,QPen 是画笔,QPainter 这个画家可以使用QPen 这个画笔在QPixmap 这个画布上绘制图形”是非常准确的。这个比喻不仅直观地表达了这三个类之间的关系,还帮助开发者更好地理解它们在Qt6图像处理和绘图功能中的作用。

布局:

  • 28
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要实现Qt中的离线百度地图,可以参照以下步骤: 1.首先下载离线百度地图的数据,可以从百度官方网站或其他第三方网站获取。这些数据通常以瓦片(tile)的形式呈现,并且按照地理坐标系统进行存储。 2.在Qt中创建地图窗口,可以使用QGraphicsView或QOpenGLWidget等控件来显示地图。根据需要将其放置在主窗口中。 3.在Qt中创建一个自定义的类来加载离线地图数据,并将其显示在地图窗口中。可以使用QImage或QPixmap来加载地图瓦片,并使用QPainter绘制地图。 4.根据用户的操作,可以实现地图的缩放、平移等功能。在地图窗口中使用鼠标事件和键盘事件来处理用户的交互操作,并在自定义的类中更新地图的显示。 5.为了提高地图的加载速度和性能,可以使用缓存机制来存储已经加载过的地图瓦片,避免重复加载。 6.如果需要在地图上显示标记、路径等信息,可以使用Qt中的图形元素类来实现。例如,使用QGraphicsItem来绘制标记点,使用QGraphicsPathItem来绘制路径等。 7.在加载离线百度地图时,需要根据地图瓦片的坐标系进行转换。百度地图采用的是墨卡托投影(Mercator Projection)坐标系,而Qt默认使用的是经纬度坐标系。可以通过相应的坐标转换算法来完成转换。 8.最后,根据具体需求,可以进一步定制和优化离线百度地图的功能和性能,例如添加地图切换、地理位置搜索等功能。 总之,通过使用Qt的图形和事件处理功能,结合合适的地图数据和坐标转换算法,就可以实现离线百度地图的显示和交互。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值