如何将一个 qApplication 的 GUI 嵌入到另一个 qApplication 的主窗口中?
Posted
技术标签:
【中文标题】如何将一个 qApplication 的 GUI 嵌入到另一个 qApplication 的主窗口中?【英文标题】:How to embed one qApplication's GUI into another qApplication's mainWindow? 【发布时间】:2016-06-06 19:27:22 【问题描述】:qApplications A & B有两个,可以用各自的主窗口分别执行。
我想实现以下目标:
1) //Open Application B.
//Inside App B's code
QProcess* proA = new QProcss();
proA->start(A.exe) //Under Windows7
2) //Instead of showing app A in a separate window.
//I would like to show it as a widget of app B's main window.
有点像谷歌浏览器。这里有一个类似的帖子:QT How to embed an application into QT widget 谈到了类似的问题。但它涉及实现您自己的窗口管理系统。有没有更简单的解决方案,因为我的两个应用程序都是 Qt 的 qApp 并且都使用 QWindow。
【问题讨论】:
QT How to embed an application into QT widget 的可能重复项 -- 检查两个答案,包含您想要的内容 您是否希望两个 QApplication 在同一个进程中运行?因为那是不可能的。但是,您可以在同一个 GUI 中将来自两个不同进程的 QWIdget 合并在一起。 @jpo38,是的!我想在同一个 GUI 中将来自两个不同进程的 qwidget 合并在一起!请写一个答案。 【参考方案1】:如果两个QApplication
s 处于不同的处理中,这绝对是可能的。
QApplication
和 QWidget
从一个进程中,找到另一个进程的 QWidget
的 winId 并将其重新设置为您自己的小部件。
要管理来自其他进程的小部件,您可以使用qtwinmigrate。最初这是为了在 Qt 小部件中嵌入 MFC 小部件(带有自己的 CWinApp
),但它也可以帮助从单独的进程嵌入 QWidget
。
这是一段工作代码:
子进程:
#include <QLabel>
#include <QWidget>
#include <QVBoxLayout>
#include <QApplication>
#include <sstream>
int main(int argc, char **argv)
QApplication app(argc,argv);
QWidget widget;
widget.setWindowTitle( "CHILD WINDOW" );
std::stringstream str;
str << "QWidget ID: " << widget.winId() << std::endl;
str << "Process Name: " << argv[0];
Qt::WindowFlags flags = widget.windowFlags();
flags |= Qt::FramelessWindowHint;
flags |= Qt::MSWindowsFixedSizeDialogHint;
flags |= Qt::SubWindow;
widget.setWindowFlags( flags );
widget.setLayout(new QVBoxLayout(&widget));
QLabel label;
widget.layout()->addWidget(&label);
label.setText(str.str().c_str());
widget.setStyleSheet( "background: red" );
widget.show();
QEvent e(QEvent::EmbeddingControl);
QApplication::sendEvent(&label, &e);
app.processEvents();
return app.exec();
父进程:
#include <QMainWindow>
#include <QApplication>
#include <QMessageBox>
#include <QVBoxLayout>
#include <QLabel>
#include <QProcess>
#include "windows.h"
#include "qtwinmigrate5/qwinhost.h"
#include <iostream>
#include <sstream>
/* The EnumChildProc callback */
static HWND hWndHandle = NULL;
static qint64 childProcessID = 0;
BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam)
DWORD dwProcessID = 0;
if (GetWindowThreadProcessId(hwnd, &dwProcessID) &&
dwProcessID == childProcessID )
char strTemp[256] = "";
GetWindowText(hwnd, strTemp, 256);
std::string str = strTemp;
if (str == "CHILD WINDOW") // sanity check
hWndHandle = hwnd;
return ( hWndHandle == NULL ); // must return TRUE; If return is FALSE it stops the recursion
void* GetChildWindowHandle( qint64 pid )
hWndHandle = NULL;
childProcessID = pid;
EnumWindows(EnumChildProc, 0);
return hWndHandle;
int main(int argc, char **argv)
QApplication app(argc,argv);
QMainWindow wnd;
wnd.setWindowTitle("That's the parent window!");
// Create child process:
QProcess process;
process.start("test_3rdparty_inprg_qtwinmigrate_child.exe");
if (process.state() != QProcess::Running)
QMessageBox::critical(NULL, "ERROR", "Unable to create child process");
return 1;
// Create qtwinmigrate widget container:
QWinHost* host = new QWinHost( &wnd );
// Get child process wiindow handle
HWND hChildWnd = NULL;
int timeout = 20;
while ((hChildWnd = (HWND)GetChildWindowHandle(process.processId())) == NULL)
// let child process more time to create and show its widget....
Sleep(200);
--timeout;
if (timeout == 0)
break;
int res = 1;
if (hChildWnd != NULL)
// attach child window handle to qtwinmigrate widget container
host->setWindow(hChildWnd);
char strTemp[256] = "";
GetWindowText(hChildWnd, strTemp, 256);
QWidget centralWidget(&wnd);
wnd.setCentralWidget(¢ralWidget);
QVBoxLayout* layout = new QVBoxLayout(¢ralWidget);
std::stringstream str;
str << "Attached data window " << std::showbase << std::hex << hChildWnd << std::endl;
str << "Window title: " << strTemp << std::endl;
str << "Widget below runs in a separate process:" << std::endl;
layout->addWidget( new QLabel( str.str().c_str(), ¢ralWidget ) );
layout->addWidget(host);
wnd.resize(400, 200);
wnd.show();
res = app.exec();
else
QMessageBox::critical(NULL, "ERROR", "Unable to find child process widget");
// kill child process
process.kill();
return res;
1- 将子进程编译为名为@987654332@ 的可执行文件。
2-将父进程编译为可执行文件
3-运行父进程,这将启动子进程,找到它的***小部件窗口句柄并将其作为子进程插入到它自己的QMainWindow
中。完成后,它将杀死子进程。
作为最终用户,很难说小部件不是同一个进程的一部分,它们是完美嵌入的(小部件的红色部分来自子进程):
【讨论】:
【参考方案2】:嗯,这就是整个 QWidget
方法的想法:可以放入容器中的所有内容都可以成为另一个应用程序的一部分。
但是,将一个完整的、未经修改的 Qt 应用程序放入另一个应用程序是不可能的:只能有一个 QApplication
实例,并且只有一个全局事件循环。
【讨论】:
以上是关于如何将一个 qApplication 的 GUI 嵌入到另一个 qApplication 的主窗口中?的主要内容,如果未能解决你的问题,请参考以下文章
我的精神分裂症控制台/gui Qt5 程序应该使用 QApplication 还是 QCoreApplication?
Pyqt5--为啥 QApplication.processEvents() 更新 GUI 失败
如何在PySide / PyQt中连接QApplication()和QWidget()对象?