Qt 5.5 Embed External Application into Qwidget

QT 5.5 embed external application into QWidget

The following achieves the desired result, the key was adding the FramelessWindowHint:

QWindow *window = QWindow::fromWinId(211812356);
window->setFlags(Qt::FramelessWindowHint);

QWidget *widget = QWidget::createWindowContainer(window);

QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(widget);
this->setLayout(layout);

Qt 5.11 - Embed external application into QWidget

Probably you are setting the layout to the wrong widget.

Take a look at this piece of code, it moves an existing window (dolphin file manager - I retrieved the window id through the xwininfo command) inside a QMainWindow:

int main( int argc, char** argv )
{
int l_result = -1;

QApplication app(argc,argv);

QMainWindow* l_main_win = new QMainWindow();
l_main_win->setWindowTitle("DOLPHIN EMBEDDED IN QT APPLICATION!");

QWindow *l_container = QWindow::fromWinId(0x4400005);
QWidget *l_widget = QWidget::createWindowContainer(l_container);

l_main_win->setCentralWidget(l_widget);
l_main_win->show();

l_result = app.exec();

return l_result;
}

and it moves my dolphin window inside a Qt main window named "DOLPHIN EMBEDDED IN QT APPLICATION!":

Sample Image

How to embed one qApplication's GUI into another qApplication's mainWindow?

It's definitely possible if the two QApplications 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):

Sample Image

Can't embed OpenGL window into QWidget with XReparentWindow

You can replace your current OpenGL window with a QGLWidget which provides an OpenGL context and can be placed into a Qt window directly.

I'm not sure Qt supports XReparentWindow calls like that. The docs don't seem to say it does, so it's probably a bad idea to use it. You could try QWidget::create() instead.



Related Topics



Leave a reply



Submit