如何将一个qApplication的GUI嵌入到另一个qApplication的mainWindow中?

时间:2016-06-06 19:27:23

标签: c++ qt

有两个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。

2 个答案:

答案 0 :(得分:4)

如果两个QApplication处理不同,那肯定是可能的。

  • 使用QApplicationQWidget
  • 创建两个流程
  • 从一个进程中,找到其他进程的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(&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-将子进程编译为名为test_3rdparty_inprg_qtwinmigrate_child.exe的可执行文件。  2-将父进程编译为可执行文件  3-运行父进程,这个进程将启动子进程,找到它的顶级窗口小部件窗口句柄并将其作为子进程插入其自己的QMainWindow。完成后,它将终止子进程。

作为最终用户,很难说小部件不是同一个过程的一部分,它们是完美嵌入的(小部件的红色部分来自子进程):

enter image description here

答案 1 :(得分:-1)

嗯,这就是整个QWidget方法的想法:可以放入容器的所有内容都可以成为另一个应用程序的一部分。

然而,将完整的,未修改的Qt应用程序放入另一个应用程序将是不可能的:只能有一个QApplication实例,并且只有一个全局事件循环。