如何将一个 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】:

如果两个QApplications 处于不同的处理中,这绝对是可能的。

创建两个进程,每个进程分别为 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- 将子进程编译为名为@9​​87654332@ 的可执行文件。 2-将父进程编译为可执行文件 3-运行父进程,这将启动子进程,找到它的***小部件窗口句柄并将其作为子进程插入到它自己的QMainWindow中。完成后,它将杀死子进程。

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

【讨论】:

【参考方案2】:

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

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

【讨论】:

以上是关于如何将一个 qApplication 的 GUI 嵌入到另一个 qApplication 的主窗口中?的主要内容,如果未能解决你的问题,请参考以下文章

我的精神分裂症控制台/gui Qt5 程序应该使用 QApplication 还是 QCoreApplication?

Pyqt5--为啥 QApplication.processEvents() 更新 GUI 失败

PyQt:如何将我的脚本转换为 GUI?

如何在PySide / PyQt中连接QApplication()和QWidget()对象?

如何在 TeamCenter 富客户端中使用 Qt Jambi 初始化 QApplication

QtGui.QApplication 和 QtCore.QCoreApplication 的区别