如何在Pyglet窗口内部嵌入渲染PyQt6窗口?
PyQt6嵌入Pyglet窗口实现方案
核心逻辑
两个GUI框架默认各自启动独立的阻塞事件循环、创建独立顶层窗口,要实现嵌入需要做两个核心处理:
- 通过操作系统原生窗口API,把PyQt创建的窗口挂载为Pyglet窗口的子窗口
- 把Qt的事件处理整合到Pyglet的帧循环中,不需要单独启动Qt的事件循环,避免线程/消息冲突
注意事项
- 初始化Qt时必须开启
AA_NativeWindows属性,否则Qt会使用非原生渲染表面,无法被挂载为子窗口 - PyQt组件需要去掉默认的系统边框,否则嵌入后会出现双层标题栏
- 不要同时启动两个框架的阻塞事件循环,Qt的事件已经通过每帧调用
processEvents()完成处理,不需要再调用app.exec(),否则会导致程序假死 - 不同操作系统的窗口挂载API有差异,以下代码做了跨平台兼容
- 如果需要实现HTML交互,只需要把示例中的基础
QWidget替换为QWebEngineView即可,所有网页加载、JS双向通信逻辑和常规PyQt开发完全一致
可直接运行的修改后代码
import sys import pyglet from pyglet.gl import * from PyQt6.QtWidgets import QApplication, QWidget from PyQt6.QtCore import Qt # 加载跨平台窗口操作依赖 if sys.platform == "win32": from ctypes import windll set_parent = windll.user32.SetParent elif sys.platform == "linux": from ctypes import cdll x11_lib = cdll.LoadLibrary("libX11.so.6") set_parent = x11_lib.XReparentWindow x11_flush = x11_lib.XFlush elif sys.platform == "darwin": import objc from AppKit import NSView # 初始化Qt配置,强制使用原生窗口 QApplication.setAttribute(Qt.ApplicationAttribute.AA_NativeWindows) app = QApplication(sys.argv) # 配置Pyglet OpenGL上下文,避免渲染冲突 gl_config = pyglet.gl.Config( double_buffer=True, depth_size=24, sample_buffers=1, samples=4 ) window = pyglet.window.Window(800, 600, "Radium", config=gl_config) # 创建PyQt组件,替换为QWebEngineView即可实现HTML能力 qt_widget = QWidget() qt_widget.resize(250, 200) # 去掉Qt窗口默认边框 qt_widget.setWindowFlags( qt_widget.windowFlags() | Qt.WindowType.FramelessWindowHint ) # 获取原生窗口句柄,完成父子窗口挂载 if sys.platform == "win32": pyglet_hwnd = window.canvas.hwnd set_parent(int(qt_widget.winId()), pyglet_hwnd) elif sys.platform == "linux": pyglet_hwnd = window.canvas.xid set_parent(pyglet_hwnd, int(qt_widget.winId()), 0, 0) x11_flush(pyglet_hwnd) elif sys.platform == "darwin": pyglet_hwnd = window.canvas.nsview qt_hwnd = int(qt_widget.winId()) pyglet_view = objc.objc_object(c_void_p=pyglet_hwnd) qt_view = objc.objc_object(c_void_p=qt_hwnd) pyglet_view.addSubview_(qt_view) # 设置Qt子窗口在Pyglet客户区的位置 qt_widget.move(20, 20) qt_widget.show() @window.event def on_resize(width, height): # 可在此处添加逻辑,让Qt组件跟随Pyglet窗口缩放自动调整位置/大小 pass @window.event def on_draw(): window.clear() # 每帧处理Qt事件,保证Qt界面交互流畅不卡顿 app.processEvents() # 此处编写原生Pyglet/OpenGL渲染逻辑 # ... @window.event def on_close(): # 退出时先销毁Qt资源避免程序崩溃 qt_widget.close() app.quit() pyglet.app.run()
常见问题处理
- 焦点异常:如果点击Qt组件(比如网页输入框)无法获得输入焦点,可以监听Pyglet的
on_mouse_press事件,判断点击坐标落在Qt组件区域时,调用qt_widget.setFocus()手动切换焦点 - 渲染花屏:如果出现OpenGL渲染冲突,可以调整Pyglet的gl_config参数,关闭多重采样或者调整深度缓冲位数
- macOS依赖:macOS平台需要先执行
pip install pyobjc-framework-AppKit安装原生桥接依赖才能正常运行
内容的提问来源于stack exchange,提问作者user15922830
相关产品推荐
相关产品推荐

