You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

不依赖PySide/PyQt,用pybind11暴露Qt6 WebView功能给Python

Qt6 WebView与Python集成问题(基于pybind11)

需求与预期目标

  • 动态控制WebView窗口:调整尺寸、全屏、无边框等样式设置
  • 支持加载本地HTML内容和远程URL
  • 实现Python与WebView中JavaScript的双向交互(调用JS函数、获取返回结果)
  • 不依赖PySide/PyQt,规避许可限制

已尝试方案及问题

使用pybind11封装C++类包裹QApplication和QWebEngineView,代码如下:

#include <pybind11/stl.h>
#include <QApplication>
#include <QWebEngineView>
#include <QString>

namespace py = pybind11;

class WebView {
public:
    WebView() {
        int argc = 0;
        char *argv[] = {nullptr};
        app = std::make_unique<QApplication>(argc, argv);
        view = std::make_unique<QWebEngineView>();
    }

    void resize(int width, int height) {
        view->resize(width, height);
    }

    void setHtml(const std::string &html) {
        view->setHtml(QString::fromStdString(html));
    }

    void setUrl(const std::string &url) {
        view->setUrl(QUrl(QString::fromStdString(url)));
    }

    void exec() {
        view->show();
        app->exec();
    }

private:
    std::unique_ptr<QApplication> app;
    std::unique_ptr<QWebEngineView> view;
};

PYBIND11_MODULE(qt_webview, m) {
    py::class_<WebView>(m, "WebView")
        .def(py::init<>())
        .def("resize", &WebView::resize)
        .def("setHtml", &WebView::setHtml)
        .def("setUrl", &WebView::setUrl)
        .def("exec", &WebView::exec);
}

编译正常,但Python导入时出现错误:
ImportError: /home/red-x/Documents/GUIEngine/MyQtWebViewApp/qt_webview.cpython-312-x86_64-linux-gnu.so: undefined symbol: qt_version_ta

同时存在以下功能缺失:

  1. 无法调整窗口样式(如无边框、全屏)
  2. 无法实现Python与JavaScript的交互
  3. 现有功能无法满足全部需求

约束条件

  • 禁止使用PySide/PyQt
  • 必须使用pybind11作为绑定工具

核心问题

  1. 如何通过pybind11将Qt窗口样式、WebView JS交互等功能暴露给Python?
  2. 有无不依赖PySide/PyQt的更优集成方式?
  3. 有无类似实现的示例或开源项目?

环境信息

OS: Windows 10 或 Ubuntu 20.04
Qt版本: 6.4.2
Python版本: 3.12
编译器: 支持C++17的g++

解决方案

1. 修复导入错误(undefined symbol: qt_version_ta)

该错误源于编译时未正确链接Qt库,需确保编译脚本/CMake配置中引入Qt6核心模块:

CMakeLists.txt示例:

cmake_minimum_required(VERSION 3.16)
project(qt_webview)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_PREFIX_PATH "/path/to/qt6") # 替换为你的Qt6安装路径

find_package(Qt6 REQUIRED COMPONENTS Core Widgets WebEngineWidgets)
find_package(pybind11 REQUIRED)

pybind11_add_module(qt_webview qt_webview.cpp)

target_link_libraries(qt_webview PRIVATE
    Qt6::Core
    Qt6::Widgets
    Qt6::WebEngineWidgets
)

g++直接编译命令:

g++ -O3 -Wall -shared -std=c++17 `python3 -m pybind11 --includes` qt_webview.cpp -o qt_webview.so `pkg-config --cflags --libs Qt6Core Qt6Widgets Qt6WebEngineWidgets`

2. 扩展窗口样式控制功能

修改C++类,添加窗口样式控制方法,并通过pybind11暴露给Python:

更新后的C++类代码:

#include <QtWidgets/QWidget> // 添加头文件

// 在WebView类中新增方法
void setFrameless() {
    view->setWindowFlags(Qt::FramelessWindowHint);
}

void setFullScreen() {
    view->showFullScreen();
}

void setWindowTitle(const std::string &title) {
    view->setWindowTitle(QString::fromStdString(title));
}

void showNormal() {
    view->showNormal();
}

更新pybind11绑定代码:

PYBIND11_MODULE(qt_webview, m) {
    py::class_<WebView>(m, "WebView")
        .def(py::init<>())
        .def("resize", &WebView::resize)
        .def("setHtml", &WebView::setHtml)
        .def("setUrl", &WebView::setUrl)
        .def("exec", &WebView::exec)
        .def("setFrameless", &WebView::setFrameless)
        .def("setFullScreen", &WebView::setFullScreen)
        .def("setWindowTitle", &WebView::setWindowTitle)
        .def("showNormal", &WebView::showNormal);
}

3. 实现Python与JavaScript交互

利用QWebEnginePage::runJavaScript结合pybind11的回调机制,实现异步JS调用与结果返回:

更新后的C++类代码:

#include <pybind11/functional.h> // 添加头文件

// 在WebView类中新增方法
void runJavaScript(const std::string &script, py::function callback) {
    view->page()->runJavaScript(QString::fromStdString(script), [callback](const QVariant &result) {
        // 将QVariant转换为Python兼容类型
        if (result.isNull()) {
            callback(nullptr);
        } else if (result.type() == QVariant::String) {
            callback(result.toString().toStdString());
        } else if (result.type() == QVariant::Int) {
            callback(result.toInt());
        } else if (result.type() == QVariant::Double) {
            callback(result.toDouble());
        } else if (result.type() == QVariant::Bool) {
            callback(result.toBool());
        } else {
            // 其他类型可按需扩展
            callback(nullptr);
        }
    });
}

更新pybind11绑定代码:

PYBIND11_MODULE(qt_webview, m) {
    // ... 原有绑定
    .def("runJavaScript", &WebView::runJavaScript);
}

Python调用示例:

from qt_webview import WebView

wv = WebView()
wv.setHtml("<html><body><script>function add(a,b){return a+b;}</script></body></html>")

# 调用JS函数并获取结果
def on_result(res):
    print("JS返回结果:", res)

wv.runJavaScript("add(2,3)", on_result)
wv.exec()

4. 替代方案与开源参考

  • Qt for Python LGPL版本:若仅需规避GPL,Qt for Python(PySide6)的LGPL版本合规,只要不修改Qt源码或静态链接即可。
  • 轻量绑定工具:qtpybind(基于pybind11的Qt绑定生成工具)可自动生成绑定代码,减少手动封装工作量。
  • 非Qt替代方案:cefpython(基于Chromium Embedded Framework),无需依赖Qt,但体积较大。

内容的提问来源于stack exchange,提问作者red X

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 05:44:55