QT 使用 QWebChannel 与 Web 端通信展示文件信息

前言

本文将展示如何使用 QWebChannel 来实现 Web 端与 QT 端之间的交互,同时会通过一个在浏览器端展示文件夹信息的简单例子来展示其具体使用,其功能如下:

  • 获取指定文件夹下的文件信息。
  • 通过使用 QT 的 QFileSystemWatcher 对指定文件夹进行监听,以实现可以获取到文件变更信息并实时展示在浏览器端。

最终实现的效果如下:

动画

本文涉及到的完整代码已上传到GitHub

阅读本文前需要对 QT 的基础知识(比如信号槽)及 QWebChannel 模块有基本的了解。

实现

QT 端

在创建完项目后,首先需要确保引入了WebChannelWebSockets模块,这里以 MSVC 为例:

image-20240131133251712

image-20240131133110870

完成以上操作后,我们首先需要创建一个WebChannelObj类用于管理所有开放给前端调用方法,头文件内容如下(为方便查看,内容有删减,后续文件都会有些许删减,完整代码可在Github查看):

class WebChannelObj : public QObject
{

signals:

    /// <summary>
    /// 信息变更事件
    /// </summary>
    /// <param name="info">文件信息</param>
    void infoChanged(const QJsonDocument& info);

public slots:

    /// <summary>
    /// 获取文件信息
    /// </summary>
    /// <returns>转为 JSON 格式的文件信息</returns>
    QJsonDocument getInfo();

};

这里的getInfo方法是直接提供给 Web 端调用的方法,需要定在slots中,infoChanged是提供给 Web 端监听的事件,需要定义在signals中。

对应的 C++ 文件如下:

// 监听的路径
QString dirPath = "D:\\code\\temp\\";

WebChannelObj* WebChannelObj::getInstance()
{
    // 配置监听
	QFileSystemWatcher* m_FileWatcher = new QFileSystemWatcher;
	m_FileWatcher->addPath(dirPath);
	connect(m_FileWatcher, &QFileSystemWatcher::directoryChanged, obj, &WebChannelObj::directoryChanged);
	return obj;
}

QJsonDocument WebChannelObj::getInfo()
{
	return dirInfo(dirPath);
}

void WebChannelObj::directoryChanged(const QString& path)
{
    // 触发变更事件
	emit infoChanged(dirInfo(path));
}

QJsonDocument WebChannelObj::dirInfo(const QString& path)
{
    // 根据给定的路径获取目录下的文件信息
    // 然后封装信息为 JSON 对象并返回
	QDir dir(path);
	dir.setFilter(QDir::AllEntries | QDir::NoDotAndDotDot);
	QFileInfoList list = dir.entryInfoList();
	QJsonArray jsonArray;
	for (auto& file : list)
	{
		QJsonObject obj;
		obj["isDir"] = file.isDir();
		obj["fileName"] = file.fileName();
		obj["fileSize"] = file.size();
		obj["lastModified"] = file.lastModified().toMSecsSinceEpoch();
		jsonArray.append(obj);
	}
	QJsonDocument doc(jsonArray);
	return doc;
}

这里使用了QFileSystemWatcher来实现对指定路径进行监听,这样就可以实时获取路径下的最新文件信息,然后通过连接directoryChangedinfoChanged事件,将信息实时返回给前端。

然后我们需要创建一个 WebSocket 服务端用于 QT 与 Web 端通信的桥梁,并在其中将QWebChannelWebSocket进行连接,内容如下:

WebChannelServer::WebChannelServer()
{
    // 将定义的 WebChannelObj 注册到 QWebChannel 中
    m_webChannel = new QWebChannel(this);
    m_webChannel->registerObject("server", WebChannelObj::getInstance());
    startServer();
}

void WebChannelServer::startServer()
{
    // 启动一个 websocket 服务, 端口为 9999
    m_websocketServer = new QWebSocketServer("Webchannel", QWebSocketServer::NonSecureMode, this);
    if (m_websocketServer->listen(QHostAddress::Any, 9999))
    {
        connect(m_websocketServer, &QWebSocketServer::newConnection, this, &WebChannelServer::onNewConnection);
    }
}

void WebChannelServer::onNewConnection()
{
    // 将 QWebChannel 与 WebSocket 进行连接
    QWebSocket* client = m_websocketServer->nextPendingConnection();
    m_webChannel->connectTo(new WebSocketTransport(client));
}

其中WebSocketTransport类是我们自定义的用于处理QWebChannelWebSocket和 Web 端通信的类,实现自QWebChannelAbstractTransport这个抽象类,其内容较为固定,就不再介绍其内容,可在GitHub中进行查看。

完成以上操作后,只需要在 main 方法中使用即可:

int main(int argc, char *argv[])
{

    QGuiApplication app(argc, argv);

    //...省略内容

    // 使用
    WebChannelServer webChannelServer;

    return app.exec();
}

到此为止, QT 端的工作就算完成了。

Web 端

相比于 QT 端,Web 端的使用就很简单了,首先我们需要先引用一个qwebchannel.js文件,这个文件由官方提供,可以在 QT 安装目录的 Examples 中找到:

image-20240131141033266

然后就可以直接使用了:

<script>
import { QWebChannel } from '@/assets/qwebchannel'

export default {
  name: 'App',
  data() {
    return {
      // 文件列表
      fileList: []
    }
  },
  mounted() {
    const websocket = new WebSocket('ws://localhost:9999')
    websocket.onopen = () => {
      new QWebChannel(websocket, channel => {
        // server 就是前文中通过 m_webChannel->
        //   registerObject("server", WebChannelObj::getInstance()); 注册的名字  
        const webChannelObj = channel.objects.server
        
        // infoChanged 是我们在 signals 中定义的提供给前端的监听事件
        // 只要有文件变更事件, 这里通过 connect 就可以获取到相应的回调事件
        webChannelObj.infoChanged.connect(data => {
          this.fileList = data
        })
        
        // getInfo 是我们在 slots 中定义的提供给前端的方法
        // 返回值需要通过回调获取  
        webChannelObj.getInfo(data => {
          this.fileList = data
        })
      })
    }
  }
}
</script>

关于上述代码的含义参考相应的注释即可,这里只需要知道如果我们想给前端提供监听事件,只需要参考 infoChanged 的定义,在前端通过 xxx.connect(data => {})就可以在回调中获取相关信息。如果想给前端提供可以直接调用的方法,只需要参考 getInfo 的定义,通过需要注意返回值也需要通过回调函数进行获取,如果方法包含参数,则按照正常传参(如果传递了对应,QT 中可以使用 QJsonObject 进行接收),同时把回调函数始终作为最后一个参数即可。

总结

本文通过一个简单的例子展示了如何使用 QWebChannel 及 WebSocket 来实现 QT 与 Web 端的通信,通过使用 QWebChannel ,我们可以很方便地在 Web 端调用 QT 中的定义方法以及实现两端的通信(例如在 Web 端通过 QT 获取摄像头然后展示在 Web 端)。本文如果有错误或不当之处,也欢迎一起交流讨论。

QWebChannel是一个用于在Qt应用程序和Web页面中进行双向通信的桥梁。在这种情况下,Qt应用程序可以通过QWebChannel将其对象暴露给JavaScript,以便JavaScript可以调用其方法和访问其属性。反过来,JavaScript也可以将其对象暴露给Qt应用程序,以便Qt应用程序可以调用其方法和访问其属性。这种双向通信可以用于在Qt应用程序和Web页面之间传递数据和事件,从而实现更紧密的集成。 以下是使用QWebChannelQt和JavaScript之间进行交互的基本步骤: 1. 在Qt应用程序中创建一个QWebChannel对象,并将其绑定到一个QWidget或QWebEngineView对象上。例如: ``` QWebChannel *channel = new QWebChannel(this); channel->registerObject("myObject", myObject); ui->webView->page()->setWebChannel(channel); ``` 其中,myObject是Qt应用程序中的一个QObject派生类的实例,它包含可以从JavaScript中调用的方法和属性。 2. 在Web页面中创建一个QWebChannel对象,并将其连接到Qt应用程序中的QWebChannel对象。例如: ``` var channel = new QWebChannel(); channel.registerObject("myObject", myObject); ``` 其中,myObject是JavaScript中的一个对象,它包含可以从Qt应用程序中调用的方法和属性。 3. 在Web页面中使用QWebChannel对象来调用Qt应用程序中的方法或访问其属性。例如: ``` channel.objects.myObject.myMethod(); var value = channel.objects.myObject.myProperty; ``` 其中,myMethod是Qt应用程序中的一个方法,myProperty是Qt应用程序中的一个属性。 4. 在Qt应用程序中使用QWebChannel对象来调用JavaScript中的方法或访问其属性。例如: ``` QWebChannel *channel = ui->webView->page()->webChannel(); QVariant result; channel->evaluateJavaScript("myObject.myMethod()", &result); qDebug() << result.toString(); ``` 其中,myMethod是JavaScript中的一个方法。evaluateJavaScript方法用于在Web页面中执行JavaScript代码,并返回结果。在本例中,结果将存储在result变量中并输出到控制台。 通过上述步骤,Qt应用程序和JavaScript之间可以进行双向通信,并共享数据和事件。这种集成可以用于实现许多不同的应用程序,例如将Qt应用程序嵌入到Web页面中,或将Web内容嵌入到Qt应用程序中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值