QT 5.9中如何使QWidget::createWindowContainer嵌入的外部程序显示标题栏及菜单栏?
在Qt 5.9中用QWidget::createWindowContainer嵌入外部程序时显示标题栏和菜单栏的解决方案
我来帮你搞定这个问题——用QWidget::createWindowContainer嵌入外部程序后标题栏、菜单栏消失,本质是系统默认会移除子窗口的系统级窗口装饰(比如标题栏、边框),毕竟子窗口不能拥有独立的窗口框架。但菜单栏如果是外部程序自身的控件(不是绑在系统标题栏上的),还是有办法保留的;如果需要标题栏功能,就得自己模拟实现。下面分两种场景细说:
场景1:保留外部程序自身的菜单栏
如果外部程序的菜单栏是它自己内部绘制的(比如用Qt、MFC做的独立控件),可以通过调整窗口样式来确保嵌入后能正常显示:
- 首先得拿到外部程序的窗口句柄:Windows下用
FindWindow,Linux用XFindWindow,macOS用CGWindowListCopyWindowInfo,这一步需要你根据系统调用对应的API。 - 然后创建Qt容器并嵌入,同时调整外部窗口的样式,让它作为子窗口时仍能显示内部控件:
// Windows平台示例代码 #include <windows.h> // 假设已经获取到外部窗口的HWND externalHwnd QWindow *externalWindow = QWindow::fromWinId((WId)externalHwnd); QWidget *container = QWidget::createWindowContainer(externalWindow, this); container->setGeometry(0, 0, 800, 600); // 设置容器的初始大小 // 调整外部窗口的样式:移除系统标题栏和边框,设置为子窗口并显示 LONG currentStyle = GetWindowLongPtr(externalHwnd, GWL_STYLE); currentStyle &= ~WS_CAPTION; // 去掉系统标题栏 currentStyle &= ~WS_THICKFRAME; // 去掉边框 currentStyle |= WS_CHILD | WS_VISIBLE; // 标记为子窗口并设置可见 SetWindowLongPtr(externalHwnd, GWL_STYLE, currentStyle); // 让外部窗口填满整个Qt容器 SetWindowPos(externalHwnd, nullptr, 0, 0, container->width(), container->height(), SWP_NOZORDER | SWP_SHOWWINDOW);
这样操作后,外部程序的内部菜单栏应该就能正常显示了,只是系统自带的标题栏会被移除。
场景2:模拟系统标题栏(带最小化/最大化/关闭功能)
如果必须要有类似系统标题栏的控制功能,因为嵌入后的窗口没法用系统自带的标题栏,你得自己在Qt里做一个自定义标题栏:
- 先做一个包含标题栏和嵌入容器的父Widget,用垂直布局把它们拼起来:
QWidget *parentWidget = new QWidget(this); QVBoxLayout *mainLayout = new QVBoxLayout(parentWidget); mainLayout->setContentsMargins(0, 0, 0, 0); mainLayout->setSpacing(0); // 自定义标题栏 QWidget *titleBar = new QWidget(parentWidget); titleBar->setFixedHeight(30); titleBar->setStyleSheet("background-color: #333; color: white;"); QHBoxLayout *titleLayout = new QHBoxLayout(titleBar); titleLayout->setContentsMargins(10, 0, 10, 0); // 标题文本 QLabel *titleLabel = new QLabel("外部程序窗口", titleBar); titleLayout->addWidget(titleLabel); titleLayout->addStretch(); // 窗口控制按钮 QPushButton *minBtn = new QPushButton("-", titleBar); QPushButton *maxBtn = new QPushButton("□", titleBar); QPushButton *closeBtn = new QPushButton("×", titleBar); titleLayout->addWidget(minBtn); titleLayout->addWidget(maxBtn); titleLayout->addWidget(closeBtn); // 嵌入外部程序的容器 QWidget *container = QWidget::createWindowContainer(externalWindow, parentWidget); // 把标题栏和容器加入布局 mainLayout->addWidget(titleBar); mainLayout->addWidget(container); parentWidget->show();
- 然后给按钮绑定功能,比如关闭按钮:
connect(closeBtn, &QPushButton::clicked, this, [=](){ // Windows平台发送关闭消息给外部窗口 SendMessage(externalHwnd, WM_CLOSE, 0, 0); parentWidget->close(); });
最小化、最大化功能可以用ShowWindow函数实现,比如ShowWindow(externalHwnd, SW_MINIMIZE);。
几个要注意的点
- 跨平台差异:上面的示例主要针对Windows,Linux和macOS的窗口API不一样,比如Linux用X11的相关函数,macOS用Cocoa API,需要针对不同平台做适配。
- 第三方程序限制:如果是嵌入第三方程序,可能人家有防嵌入的机制,或者菜单栏就是绑在系统标题栏上的,这种情况下你可能没法直接保留菜单栏,只能通过模拟菜单或者IPC调用外部程序的菜单功能来实现。
内容的提问来源于stack exchange,提问作者qiujie wei
相关产品推荐
相关产品推荐

