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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 20:12:22