2

There are two qApplications A & B, they can be executed separately with their own main window.

I would like to achieve the following:

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.

Sort of like google chrome. A similar post here:QT How to embed an application into QT widget talked about the similar problem. But it involves implement your own window management system. Is there simpler solutions as both my app are Qt's qApp and both uses QWindow.

Community
  • 1
  • 1
Nyaruko
  • 4,329
  • 9
  • 54
  • 105
  • 1
    Possible duplicate of [QT How to embed an application into QT widget](http://stackoverflow.com/questions/18472840/qt-how-to-embed-an-application-into-qt-widget) -- check both answers, what you want is included – coyotte508 Jun 06 '16 at 19:32
  • 1
    Are you expecting to have the two QApplication running in the same process? Because that's impossible. However, you can merge QWIdgets from two different processes together within the same GUI. – jpo38 Jun 07 '16 at 06:39
  • @jpo38, yes! I want to merge qwidgets from two different processes together within the same GUI! Please kindly write an answer. – Nyaruko Jun 07 '16 at 07:09

2 Answers2

5

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(&centralWidget);

        QVBoxLayout* layout = new QVBoxLayout(&centralWidget);

        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(), &centralWidget ) );
        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):

enter image description here

Community
  • 1
  • 1
jpo38
  • 20,821
  • 10
  • 70
  • 151
-1

well, that's the idea of the whole QWidget approach: Everything that can be put in a container can be part of another application.

However, putting a complete, unmodified Qt application into another one will not be possible: There can only be one QApplication instance, and only one global event loop.

Marcus Müller
  • 34,677
  • 4
  • 53
  • 94