共享屏幕-基于QT

目录

屏幕共享的实现与应用

一、简介

二、设计软件界面

二、技术实现

三、应用场景

在线教育:

远程演示:


屏幕共享的实现与应用

一、简介

屏幕共享包括屏幕采集和视频流推送这两部分功能。此次软件只在客户端方面做了优化,采用HTTP协议解决用户的软件安装下载困难,最大程度节省用户的安装软件。下面以 QT为例,介绍整体的设计框架;

二、设计软件界面

设计代码: 

#include "widget.h"
#include "ui_widget.h"
#include <QGraphicsOpacityEffect>
#include <QMouseEvent>


Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    setWindowFlags(Qt::FramelessWindowHint);
    ui->label->setPixmap(QPixmap(":/ll.bmp"));
    ui->label->setScaledContents(true);

    ui->toolButton->setIcon(QIcon(":/close.png"));
    ui->toolButton_2->setIcon(QIcon(":/minus.png"));

    /*基本设置*/
    this->setWindowIcon(QIcon(":/log.png")); //设置图标
    this->setWindowTitle("屏幕共享");
    //隐藏边框
    ui->textEdit_ip->setFrameStyle(QFrame::NoFrame);


    QGraphicsOpacityEffect *opacity = new QGraphicsOpacityEffect;
     opacity->setOpacity(0.4); //透明范围同窗口透明度
     ui->pushButton_start->setGraphicsEffect(opacity);

     QGraphicsOpacityEffect *opacity3 = new QGraphicsOpacityEffect;
      opacity3->setOpacity(0.5); //透明范围同窗口透明度
     ui->textEdit_ip->setGraphicsEffect(opacity3);


    /*获取本机IP地址添加到列表进行显示*/
        QList<QHostAddress> list = QNetworkInterface::allAddresses();
        for(int i=0;i<list.count();i++)
        {
            QHostAddress addr=list.at(i);
            if(addr.protocol() == QAbstractSocket::IPv4Protocol)
            {
                ui->textEdit_ip->append(addr.toString());
            }
        }

        //刷新在线人数
        timer = new QTimer(this);
        connect(timer, SIGNAL(timeout()), this, SLOT(timer_update()));
        timer->start(100);

        //***托盘***
            tray= new QSystemTrayIcon(this);//初始化托盘对象tray

            connect(tray,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),this,SLOT(show_Widget(QSystemTrayIcon::ActivationReason)));

            tray->setIcon(QIcon(QPixmap(":/log.png")));//设定托盘图标
            tray->setToolTip("局域网屏幕共享"); //提示文字
            restoreAction = new QAction("打开", this);
            connect(restoreAction, SIGNAL(triggered()), this, SLOT(show()));
            quitAction = new QAction("退出", this);
            connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));

            trayMenu = new QMenu(this);
            trayMenu->addAction(restoreAction);
            trayMenu->addSeparator();
            trayMenu->addAction(quitAction);
            tray->setContextMenu(trayMenu);

}
void Widget::show_Widget(QSystemTrayIcon::ActivationReason reason)
{
    switch(reason)
    {
    case QSystemTrayIcon::Trigger://单击托盘图标
        this->showNormal(); //还原界面
        break;
    case QSystemTrayIcon::DoubleClick://双击托盘图标
        this->showNormal();//还原界面
        break;
    default:
        break;
    }
}

void Widget::mousePressEvent(QMouseEvent *event) {
    if(event->button() == Qt::LeftButton){    //如果有鼠标左键按下
        m_dragPosition = event->globalPos()   //鼠标相对于屏幕左上角的位置
                - frameGeometry().topLeft();  //时钟窗体左上角的位置
        event->accept();                      //接受事件
    }
}

void Widget::mouseMoveEvent(QMouseEvent *event) {
    if(event->buttons() & Qt::LeftButton){     //有按键按下 同时是鼠标左键
        move(event->globalPos() - m_dragPosition);
    }
}

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

void Widget::on_pushButton_start_clicked()
{
    if(ui->pushButton_start->text()=="启动屏幕共享")
    {
        //监听服务器
        if(server.listen(QHostAddress::Any,8888)!=true)
        {
            QMessageBox::question(this, tr("提示"),tr("服务器监听设置失败.\n"),QMessageBox::Ok);
            return;
        }
        thread_run_flag=true; //视频传输线程
        ui->pushButton_start->setText("停止屏幕共享");
    }
    else
    {
        server.close(); //关闭服务器

        thread_run_flag=false;//视频传输线程

        //设置按钮文本
        ui->pushButton_start->setText("启动屏幕共享");
    }

}
/*
 * @brief Widget::timer_update
 * 在线人数
 */
void Widget::timer_update()
{
    //显示在线人数
    ui->lcdNumber->display(fd_list.fd_count());

}


void Widget::on_toolButton_clicked()
{
    close();
}

void Widget::on_toolButton_2_clicked()
{
    //设置窗口最小化到托盘
        this->hide();
        QString title="小昌伟";
        QString text="局域网屏幕共享";
        tray->show();//让托盘图标显示在系统托盘上
        tray->showMessage(title,text,QSystemTrayIcon::Information,1000); //最后一个参数为提示时长,默认10000,即10s
}

操作使用:

  1. 在需要共享屏幕设备上安装此软件,启动共享屏幕
  2. 其他用户连接设备输入网址如下:

本地设备测试:http://127.0.0.1:8888/?user=xlc&pass=12345678     

用户设备: http://192.168.2.9:8888/?user=xlc&pass=12345678 

忘记用户密码可以使用:http://127.0.0.1:8888/?GET/usr 

用户获取到屏幕信息显示当前人数

 

用户只需在网页查看屏幕信息无需其他操作如图所示:

二、技术实现

  1. 使用S/c模型创建局域共享数据通道、搭建服务器模型。

#ifndef TCP_SERVER_H
#define TCP_SERVER_H

#include <QTcpServer>
#include <QReadWriteLock>
#include <QList>



/*
    存放连接上服务器的节点
*/
class SocketFdList
{
private:
    QReadWriteLock lock;
    QList<qintptr> fd;
public:
    SocketFdList()
    {
        fd.clear();
    }

    //向队列里插入一条数据
    void add_fd(qintptr data)
    {
        lock.lockForWrite();
        fd.append(data);
        lock.unlock();
    }
    //卸载数据
    void Del_fd(qintptr data)
    {
        lock.lockForWrite();
        for(int i=0;i<fd.count();i++)
        {
            if(fd.at(i)==data)
            {
                fd.removeAt(i); //卸载节点
            }
        }
        lock.unlock();
    }
    //返回数量
    int fd_count(void)
    {
        int cnt;
        lock.lockForRead();
        cnt = fd.count();
        lock.unlock();
        return cnt;
    }
};

class tcp_server :public QTcpServer
{

public:
    tcp_server();
protected:
    void incomingConnection(qintptr socketDescriptor);
};

extern class SocketFdList fd_list;
#endif // TCP_SERVER_H



以上是头文件
//


#include "tcp_server.h"
#include "tcp_thread.h"

class SocketFdList fd_list;

tcp_server::tcp_server()
{


}


//重写TCP服务器的虚函数,处理新连接上的客户端
void tcp_server::incomingConnection(qintptr socketDescriptor)
{
    tcp_thread *thread = new tcp_thread(socketDescriptor);
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); //销毁对象
    thread->start();
}

  1. 创建多线程任务,满足多个设备访问,满足并发实时性
#ifndef TCP_THREAD_H
#define TCP_THREAD_H

#include <QThread>
#include "tcp_server.h"
#include <QObject>
#include <QTcpSocket>
#include <QFile>
#include <QtNetwork>
#include "widget.h"

#include <QPixmap>
#include <QGuiApplication>
#include <QScreen>
extern QString pix_size;
extern bool thread_run_flag;

class tcp_thread : public QThread
{
    Q_OBJECT
public:
    tcp_thread(int socketDescriptor);
    virtual ~tcp_thread();


    void run();
    QTcpSocket *tcpSocket;
    int SendFileData(char *buff, QString file_path, const char *type);
    int SendFileData(const char *buff,const char *type);
    int SendImageData(char *buff);
    char buff[1024];
private:
    int socketDescriptor;
    QString text;
};

#endif // TCP_THREAD_H

//
#include "tcp_thread.h"
#include <QDebug>

#include "ui_widget.h"

QString pix_size(100);
//线程运行标志
bool thread_run_flag=true;

tcp_thread::tcp_thread(int socketDescriptor)
    :socketDescriptor(socketDescriptor)
{
    //保存连接的套接字
    fd_list.add_fd(socketDescriptor);


}

tcp_thread::~tcp_thread()
{
    //卸载连接的套接字
    fd_list.Del_fd(socketDescriptor);
//    //关闭连接
    tcpSocket->close();
    delete  tcpSocket;
}

void tcp_thread::run()
{
    tcpSocket=new QTcpSocket;
    /*使用socketDescriptor套接字初始化QAbstractSocket*/
    if(!tcpSocket->setSocketDescriptor(socketDescriptor))
    {
        return;
    }
    //读取接收的数据
       QString text;
       if(tcpSocket->waitForReadyRead())
       {
           text=tcpSocket->readAll();
       }

       //处理浏览器的请求
       if(text.contains("GET/usr", Qt::CaseInsensitive))
       {
           SendFileData(buff,":/usr.txt","text/html");
       }
       else if(text.contains("user=xlc&pass=12345678", Qt::CaseInsensitive))
       {
               //视频共享
               SendImageData(buff);
       }

}

/*
 * 向浏览器响应请求数据
 */
int tcp_thread::SendFileData(char *buff,QString file_path,const char *type)
{
    qint64 size=0;
    /*1. 读取文件*/
    QFile file(file_path);
    if(file.open(QIODevice::ReadOnly)!=true)return -1;
    size=file.size(); //得到文件大小
    QByteArray byte=file.readAll(); //读取所有数据
    file.close();//关闭文件
    /*2. 构建响应格式字符串*/
    sprintf(buff,"HTTP/1.1 200 OK\r\n"
                 "Content-type:%s\r\n"
                 "Content-Length:%lld\r\n"
                 "\r\n",type,size);
    /*3. 向客户端发送响应请求*/
    if(tcpSocket->write(buff,strlen(buff))<=0)return -2;
    tcpSocket->waitForBytesWritten();  //等待写
    /*4. 向客户端发送响应实体数据*/
    if(tcpSocket->write(byte)<=0)return -3;
    tcpSocket->waitForBytesWritten();  //等待写
    return 0;
}




使用HTTP协议使客户端在浏览器获取共享设备视频流信息

/*
向客户端循环发送图片数据流
*/
int tcp_thread::SendImageData(char *buff)
{
    /*1. 构建响应格式字符串*/
    sprintf(buff,"HTTP/1.0 200 OK\r\n"
                "Server: wbyq\r\n"
                "Content-Type:multipart/x-mixed-replace;boundary=boundarydonotcross\r\n"
                "\r\n"
                "--boundarydonotcross\r\n");
    /*2. 向客户端发送响应请求*/
    if(tcpSocket->write(buff,strlen(buff))<=0)return -2;
    tcpSocket->waitForBytesWritten();  //等待写
    /*3. 循环发送数据*/
    while(thread_run_flag)
    {
        QBuffer data_buff;
        QPixmap pixmap;
        QScreen *screen = QGuiApplication::primaryScreen();
        pixmap=screen->grabWindow(0); //获取当前屏幕的图像
        //pixmap = pixmap.scaled(w,h, Qt::KeepAspectRatio);
        pixmap.save(&data_buff,"jpg",80);
        QByteArray image_data=data_buff.data();

        /*4. 向浏览器发送响应头*/
        sprintf(buff,"Content-type:image/jpeg\r\n"
                     "Content-Length:%d\r\n"
                     "\r\n",image_data.size());
        if(tcpSocket->write(buff,strlen(buff))<=0)break;
        tcpSocket->waitForBytesWritten();  //等待写

        /*5. 发送实体数据*/
         if(tcpSocket->write(image_data)<=0)break;
         tcpSocket->waitForBytesWritten();  //等待写

        /*6. 发送边界符*/
        sprintf(buff,"\r\n--boundarydonotcross\r\n");
        if(tcpSocket->write(buff,strlen(buff))<=0)break;
        tcpSocket->waitForBytesWritten();  //等待写

        //等待一段时间
        msleep(5);
    }
    return 0;
}

三、应用场景

在线教育:

适用于大班课、小班课等多种教育场景,老师端可以通过屏幕共享将上课需要的课件,资料共享给学生,让教学变得更加高效,提高效率节省时间。

远程演示:

在进行远程协作或操作演示时,可以通过采集屏幕和窗口的内容,直观演示具体操作步骤,帮助他人快速理解。屏幕共享允许的在线演示是组织与客户和客户互动的完美方法。借助屏幕共享应用程序,不仅销售人员可以展示他们的产品,而且他们还可以通过提供PC键盘或鼠标的远程控制来邀请客户体验软件程序等项目。这是屏幕共享工具的最佳好处之一。

  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Qt是一个跨平台的C++开发框架,可以用于实现远程桌面共享与控制的功能。 要实现远程桌面共享,可以使用Qt提供的网络模块,通过TCP/IP协议建立连接,将远程主机的屏幕信息发送到本地主机,然后在本地主机上显示远程主机的屏幕内容。使用Qt的图像处理模块,可以实时地对远程主机的屏幕图像进行解码和渲染,保证图像的清晰度和流畅度。通过与远程主机建立的连接,可以实现双向通信,使得远程主机的操作能够在本地主机上同步显示。 要实现远程桌面控制,可以通过在本地主机上发送指令到远程主机,模拟用户的操作。例如,本地主机上的鼠标移动和点击事件可以被捕捉到,并通过网络传输到远程主机,远程主机接收到这些事件后,模拟鼠标的移动和点击操作。类似地,本地主机上的键盘输入也可以通过这种方式发送到远程主机。 为了提高远程桌面共享与控制的效率和安全性,可以使用Qt的多线程和加密模块。通过多线程的方式可以在接收屏幕图像和处理用户指令的过程中互不干扰,提高系统的响应速度。通过加密模块可以对传输的数据进行加密和解密,保护用户的隐私和远程主机的安全。 总之,通过使用Qt的网络、图像处理、多线程和加密模块,可以实现远程桌面共享与控制的功能,并提供高效、安全的远程访问体验。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值