It's definitely possible if the two QApplication
s are in different processed.
- Create two process each with it's
QApplication
and QWidget
- From one process, find the winId of the other processe's
QWidget
and reparent it to your own widget.
To manage the widget from the other process reparented to yours, you may use qtwinmigrate. Originally this was meant to embed a MFC widget (with its own CWinApp
) in a Qt widget, but it can also help embedding a QWidget
from a separate process.
Here is a piece of working code:
Child process:
#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();
}
Parent process:
#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- Compile child process into an executable named test_3rdparty_inprg_qtwinmigrate_child.exe
.
2- Compile parent process into an executable
3- Run parent process, this one will start the child process, find it's top level widget window handle and insert it within its own QMainWindow
as a child. When done, it will kill the child process.
As a end user, it's hard to tell the widgets are not part of the same process, they are perfectly embedded (the red part of the widget comes from the child process):
