Qt5下多进程界面的嵌套

关于多进程嵌套,Qt4一直使用QX11Embed,在Qt5被舍弃后,一直无法找到可跨平台的完全的替代品,特别是QX11EmbedWidget::embedInto函数,一直无法找到替代,在这里,实现思路为,依旧使用QProcess,由宿主创建QProcess调用子进程,并且传入宿主WId(这里为了让子进程把parent绑定到宿主上,避免还没绑定上布局就提前show出来了,不美观),在子进程完全启动后,使用IPC把子进程的WId传入到宿主中,宿主收到子进程Wid后,解析为Widget,并放入布局内。在这里,IPC可以有很多中方式,标准输入输出,管道,共享内存,套接字之类的,这里博主选了一个代码量最轻量的方式,QLocalSocket,网络套接字来完成进程间的交互。下面就po出代码吧。

宿主main.cpp

#include "WaitingBarWin.h"
#include <QApplication>


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    WaitingBarWin w;
    w.show();


    return a.exec();
}
WaitingBarWin.h
#ifndef WAITINGBARWIN_H
#define WAITINGBARWIN_H

#include <QWidget>
#include <QLocalServer>
#include <QLocalSocket>
namespace Ui {
class WaitingBarWin;
}

class QProcess;

class WaitingBarWin : public QWidget
{
    Q_OBJECT

public:
    explicit WaitingBarWin(QWidget *parent = 0);
    ~WaitingBarWin();

private:
    Ui::WaitingBarWin *ui;
    QProcess *m_process;
    QLocalServer server;
private slots:
    void slot_createWaitingBar();
};
#endif // WAITINGBARWIN_H

WaitingBarWin.cpp

#include "waitingbarwin.h"
#include "ui_waitingbarwin.h"

#include <QProcess>
#include <QDebug>
#include <QWindow>

WaitingBarWin::WaitingBarWin(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::WaitingBarWin),
    m_process(nullptr)
{
    ui->setupUi(this);
    if(m_process == nullptr)
    {
         QString cmd = "D:\\Code\\build-SWitchControl-Desktop_Qt_5_12_3_MinGW_64_bit-Debug\\debug\\SWitchControl.exe";//子程序执行文件地址
        QStringList argList;
        argList << QString::number(this->winId());//把父窗口的id给子进程传递过去
        m_process = new QProcess(this);//使用进程运行子进程窗口
        QLocalServer::removeServer("SWitchControl");
        if(server.listen("SWitchControl"))
        {
            connect(&server,&QLocalServer::newConnection,[&](){
                QLocalSocket* clientConnection = server.nextPendingConnection();
                connect(clientConnection,&QLocalSocket::readyRead,this,&WaitingBarWin::slot_createWaitingBar);
                    });
        }
        m_process->startDetached(cmd, argList);
    }
}

WaitingBarWin::~WaitingBarWin()
{
    delete ui;
    m_process->terminate();//在父窗口关闭时,主动终止子窗口进程
    m_process->waitForFinished(50);
}

void WaitingBarWin::slot_createWaitingBar()
{
    QLocalSocket* clientConnection = static_cast<QLocalSocket*>(sender());
    QTextStream textStream(clientConnection);
    QString wId = textStream.readAll().trimmed();
    QWindow *childWin = QWindow::fromWinId(wId.toULongLong());
    if(childWin)
    {
        QWidget *widget = QWidget::createWindowContainer(childWin);//获取一个子进程窗口的widget
        ui->verticalLayout->addWidget(widget);//这里是可以使用布局器管理子进程窗口的,不管理的话就在坐标0,0处
    }
}

在这里,宿主进程代码就算完成了,还有个WaitingBarWin.ui文件,这里就不贴出了,ui文件里面其实就是放了一个布局控件,叫做verticalLayout。

接下来是子进程的代码

子进程main.cpp

#include <QApplication>
#include <QDebug>
#include <stdio.h>
#include <QLabel>
#include <QWindow>
#include <QLocalSocket>
int main(int argc, char *argv[])
{
    if(argc == 2)
    {
        QApplication a(argc, argv);

        //这里是子窗口的顶层窗口
        QLabel w;
        w.setText("isMe");
        //end

        WId wid = WId(QString(argv[1]).toInt());//通过参数列表获取父进程窗口的WinId
        QWindow *window = QWindow::fromWinId(wid);//获取父进程窗口

        w.setProperty("_q_embedded_native_parent_handle", QVariant(wid));//设置属性,这句是必须的

        w.winId();//必须调用一次,生成winId
        w.windowHandle()->setParent(window);//设置父窗口
        w.show();//最后调用show,提前调用qt会为其生成窗口控件,这样就会和你原本想要嵌入进的父进程界面产生冲突

        QLocalSocket socket;
        socket.connectToServer("SWitchControl");
        if(socket.waitForConnected())
        {
            QString winId = QString::number(w.winId());
            QTextStream(&socket)<<winId;
            socket.flush();
            if(socket.waitForBytesWritten())
            {
                socket.disconnectFromServer();
            }
        }
        return a.exec();
    }

    return 0;
}

这里就算全部完成了。不懂可以留言或者评论。

  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值