QT上位机:局域网特定设备ip查询和显示


运行环境:win10

QT版本:5.11.3


最近在研究QT如何将局域网的设备IP显示在列表中,然后通过双击打开,调用web浏览器访问一个固定的网址。因为这里是特定的设备,并且是局域网中的,那么我们可以通过设计一个协议来处理这个问题。什么协议最适合这样的场景呢?熟悉网络协议的童鞋一直知道UDP有个广播地址。当广播一条消息时,处于统一局域网中的UDP的客户端或者是服务器都能收到这条消息。知道大概的方向后,下面就是开始撸代码了:

首先,先打开QT Creator,新建一个工程,暂且名字为qt_iot_dev_find。建立好工程后,我们打开工程中mainwindows.ui,进行页面布局。这里的话,涉及的业务比较简单,就三个控件,页面布局如下:

因为这个工程要涉及到网络编程,所以我们要打开工程文件qt_iot_dev_find.pro,在第8行添加一行代码:

QT += network

添加完了之后,我们打开mainwindow.h头文件,修改头文件如下:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

#include <QUdpSocket>//添加头文件

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    void list_init();//列表初始化
    void udp_server_init();//upd服务器初始化
    void iot_dev_ip_item_add(QString ip,QString data);//将获取到的ip和数据,加入到列表中
    QUdpSocket *udp_server;
private:
    Ui::MainWindow *ui;

//添加槽函数
private slots:
    void udp_receive_data_handler();//自己添加的slot,在收到upd消息后,会自动调用该函数

    void on_search_dev_pushButton_clicked();//该函数是自动添加的,按键连接的槽函数
};

#endif // MAINWINDOW_H

然后打开mainwindow.cpp,修改cpp文件如下:

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

#include <QListWidgetItem> //添加头文件,我们是一个item一个item的插入


#define UDP_SERVER_PORT    12345
#define VALID_DATA         "ping_request" //有效数据.当前udp服务器认的有效数据,客户端只需要发这个,就可以显示在列表中
#define MAX_NUM             5             //显示最大为5,这个随意更改

static unsigned char g_connect_count = 0;//连接数统计
static QString ip_all[MAX_NUM][32];//用来缓存连接的ip

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    list_init();
    udp_server_init();
}

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

//列表初始化
void MainWindow::list_init()
{
    //初始化列表头,暂定为ip_addr和data
    QListWidgetItem *list_head = new QListWidgetItem("      ip_addr     \t     data",ui->dev_infor_listWidget);
    ui->dev_infor_listWidget->insertItem(1,list_head);
    //
}

//Upd服务器初始化
void MainWindow::udp_server_init()
{
    //创建一个udp server对象
    udp_server = new QUdpSocket(this);
    //绑定端口号为12345
    udp_server->bind(UDP_SERVER_PORT,QUdpSocket::ShareAddress);
    //连接到slots,有客户端的消息到来时,会自动调用udp_receive_data_handler
    connect(udp_server,SIGNAL(readyRead()),this,SLOT(udp_receive_data_handler()));

}

void MainWindow::udp_receive_data_handler()
{
    QHostAddress udp_client_address;//声明一个QHostAddress对象
    unsigned short int udp_client_port = 0;//客户端端口号
    QByteArray udp_datagram;//upd client 发来的数据,里面包含内容和大小

    while( udp_server->hasPendingDatagrams() )
    {
        udp_datagram.resize( udp_server->pendingDatagramSize());

        udp_server->readDatagram(udp_datagram.data(),udp_datagram.size(), &udp_client_address, &udp_client_port);

        //比较数据是否为有效数据
        if(strcmp(udp_datagram.data(),VALID_DATA) == 0)
        {
            //注意这里的ip显示的格式是这样的,我们需要转换一下"::ffff:192.168.xxx.xxx" ==> "192.168.xxx.xxx"
            QString ip_addr_temp =  udp_client_address.toString();
            QString ip_addr;
            int i = 0;
            //填充ip地址
            for(i = 7; ip_addr_temp[i] != '\0'; i ++ )
            {
                ip_addr[i-7] = ip_addr_temp[i];
            }
            //插入列表
            iot_dev_ip_item_add(ip_addr + QString(":")+ QString().number(udp_client_port),udp_datagram.data());
        }
        //非法数据,不处理

    }
}

//将获取到的ip,加入到列表中
void MainWindow::iot_dev_ip_item_add(QString ip,QString data)
{
    //大于最大连接数,则不进行插入
    if(g_connect_count >= MAX_NUM)
        return ;
    //相同IP和端口,只显示一个,这个值是不会重复的
    for(unsigned char i = 0; i < MAX_NUM; i ++)
    {
        if(ip == *ip_all[i])
        {
            //这里添加调试信息打印
            qDebug() << "*****************************";
            qDebug() << "i = " << i;
            qDebug() << "buff:client_addr:" << *ip_all[i];
            qDebug() << "current client_addr:" << ip;

            return;
        }
    }
    //没有找到相同的,插入
    ip_all[g_connect_count][0] = ip;
    g_connect_count = g_connect_count + 1;
    QListWidgetItem *list_iot_dev = new QListWidgetItem(ip + QString("\t") + data,ui->dev_infor_listWidget);
    ui->dev_infor_listWidget->insertItem(1,list_iot_dev);

}

void MainWindow::on_search_dev_pushButton_clicked()
{
   for(unsigned char i = 0; i < g_connect_count; i ++)
   {
       ip_all[i][0] = "";//清空缓冲区
   }
   g_connect_count = 0;
   ui->dev_infor_listWidget->clear();
   list_init();//重新初始化
}

测试情况如下:(测试客户端使用通信猫,后续的话,我会将客户端这部分的代码进行补充,现在还没有写好)

运行程序,效果如下:

打开通信猫软件,选择udp,然后设置广播的方式:

设计的知识归纳:

1.QT UDP的使用

2.QListWidget的使用

3.QListWidgetItem的使用

使用例子都在源代码里了。好好码一次,加深理解即可~~~~

如果这篇文章,对你有帮助,就点个赞再走哈~~~

  • 11
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
QT上位机可以通过使用OpenCV库来解析和显示ESP32cam通过IP传输过来的视频流。 步骤如下: 1. 在QT工程中添加OpenCV库的头文件和链接库。 2. 创建QT界面,包含一个QLabel控件用于显示视频流。 3. 使用QT的信号与槽机制,绑定一个定时器信号和槽函数,定时从IP地址获取视频流数据,解析并显示在QLabel控件中。 4. 在槽函数中,使用OpenCV库中的VideoCapture类读取视频流数据,并使用cv::imshow函数显示在QLabel控件中。 5. 为了实现流畅的视频播放,可以使用多线程来处理视频流数据,解析和显示分别在不同的线程中进行。 示例代码如下: ``` #include <QMainWindow> #include <QTimer> #include <QLabel> #include <opencv2/opencv.hpp> class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void updateVideo(); private: QTimer *m_timer; QLabel *m_display; cv::VideoCapture m_camera; }; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { m_timer = new QTimer(this); m_display = new QLabel(this); setCentralWidget(m_display); m_camera.open("http://192.168.1.100:81/stream"); m_camera.set(cv::CAP_PROP_FRAME_WIDTH, 640); m_camera.set(cv::CAP_PROP_FRAME_HEIGHT, 480); connect(m_timer, SIGNAL(timeout()), this, SLOT(updateVideo())); m_timer->start(30); // 30ms定时器 } MainWindow::~MainWindow() { m_timer->stop(); delete m_timer; delete m_display; } void MainWindow::updateVideo() { cv::Mat frame; m_camera.read(frame); cv::imshow("Video", frame); m_display->setPixmap(QPixmap::fromImage(QImage(frame.data, frame.cols, frame.rows, frame.step, QImage::Format_RGB888).rgbSwapped())); } ``` 在上面的示例代码中,使用VideoCapture类打开IP地址为"http://192.168.1.100:81/stream"的视频流,并设置分辨率为640x480。定时器每30ms触发一次updateVideo槽函数,该函数中读取视频流数据并使用imshow函数在本地显示。最后将Mat类型数据转换为QImage类型数据,并在QLabel控件中显示

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值