前提,qt 提供的例程依赖,websocket ,这里不包含websokcet
在同一进程中,实现底层 qt代码 与 html 界面分离。
一、 定义类 MyChannel 实现接口定义。
class MyChannel : public QObject
{
Q_OBJECT
public:
explicit MyChannel(QObject *parent = 0);
Q_INVOKABLE void doSomeThing();
Q_INVOKABLE void receiveText(const QString& txt);
signals:
void sendText(QString txt);
public slots:
};
MyChannel::MyChannel(QObject *parent) : QObject(parent)
{
QTimer::singleShot(3000,this,&MyChannel::doSomeThing);
}
void MyChannel::doSomeThing()
{
emit sendText("doSomeThing!!!");
}
void MyChannel::receiveText(const QString& txt)
{
qDebug() << txt;
QTimer::singleShot(1000,this,&MyChannel::doSomeThing);
}
这里需要加上 Q_INVOKABLE 被调用,否则可能会报错,未定义 js: Uncaught TypeError: MyChannel.receiveText is not a function
二、主窗口添加 webView
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
webView(nullptr)
{
ui->setupUi(this);
webView = new QWebEngineView(this);
setCentralWidget(webView);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::setWebChannel(QWebChannel* ch)
{
webView->page()->setWebChannel(ch);
// 获取当前应用程序的运行目录
QString currentDir(QCoreApplication::applicationDirPath());
qDebug() << currentDir;
// 构建HTML文件的相对路径
QString relativePath = "index.html";
QUrl url = QUrl::fromLocalFile(QDir(currentDir).absoluteFilePath(relativePath));
// 加载HTML文件
webView->load(url);
// 设置窗口自适应大小
webView->showMaximized();
}
需要注意,setWebChannel(ch) 设置通道,在 load("xx.html") 之前,确保通道被创建。
三、 main 函数
QApplication a(argc, argv);
QWebChannel channel;
MyChannel myCh;
channel.registerObject(QStringLiteral("MyChannel"), &myCh);
MainWindow w;
w.setWebChannel(&channel);
w.show();
registerObject 将 MyChannel 类注册给 channel,再将 设只给 web->page(),
四、设置 index.html
function output(message)
{
var output = document.getElementById("output");
output.innerHTML = output.innerHTML + message + "\n";
}
window.onload = function() {
output("WebSocket connected, setting up QWebChannel.");
new QWebChannel(qt.webChannelTransport, function(channel) {
// make MyChannel object accessible globally
window.MyChannel = channel.objects.MyChannel;
document.getElementById("send").onclick = function() {
var input = document.getElementById("input");
var text = input.value;
if (!text) {
return;
}
output("Sent message: " + text);
input.value = "";
MyChannel.receiveText(text);
}
MyChannel.sendText.connect(function(message) {
output("Received message: " + message);
});
MyChannel.doSomeThing();
MyChannel.receiveText("Client connected, ready to send/receive messages!");
output("Connected to WebChannel, ready to send/receive messages!");
});
}
这里的 QWebChannel(qt.webChannelTransport ... 是默认写法,由 webEngine 设置的通道,
Transport 如果要自定义,需要添加 sent(), onmessage() 方法。
从官方例程中可以看到, QWebChannelAbstractTransport 【官】
class QJsonObject;
class Q_WEBCHANNEL_EXPORT QWebChannelAbstractTransport : public QObject
{
Q_OBJECT
public:
explicit QWebChannelAbstractTransport(QObject *parent = Q_NULLPTR);
virtual ~QWebChannelAbstractTransport();
public Q_SLOTS:
virtual void sendMessage(const QJsonObject &message) = 0;
Q_SIGNALS:
void messageReceived(const QJsonObject &message, QWebChannelAbstractTransport *transport);
};
结果验证:
控制台输出: