【问题标题】:Executing a qt application inside qt application在 qt 应用程序中执行一个 qt 应用程序
【发布时间】:2016-10-31 18:13:25
【问题描述】:

我正在尝试将几个 qt 应用程序嵌入到另一个仅用作容器的应用程序中。 (我用的是linux)

让我们调用应用程序容器container和一个执行的表单容器utility

容器中,我有一个QTabWidget,在这个QTabWidget 中,我有一个带有一个名为utility1Widget 的小部件的Tab。

我想在utility1Widget 中查看utility 的GUI。

Edit2:最初的方法是错误的,我把它放在这里以供将来参考,但我的单独答案中有一个有效的实现。

我尝试获取utility1Widget 的WId 并在utility 开始时将其作为arg 发送,但未成功,类似于:

utility.cpp

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    int containerWinId;
    QWidget *parent=NULL;
    if(argc==2) {
        containerWinId=atoi(argv[1]);
        parent = QWidget::find(containerWinId);
    }

    MarinaWindowClient w(parent);

    w.show();
    printf("Starting client window. Do you see something?\r\n");
    fflush(stdout);
    return a.exec();
}

因此,utility1Widget 为空,但实用程序 GUI 没有出现在任何地方。

实用程序进程以这种方式从容器启动:

mainContainer.cpp

marinaContainer::mainContainer(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::mainContainer)
{
    ui->setupUi(this);
    WId myWinId=ui->utility1Widget->winId();
    char cmd[1000];
    sprintf(cmd," %d",myWinId);
    QProcess *myProcess = new QProcess(this);
    myProcess->start("utility1", QStringList(cmd));

    printf("Client started\r\n");
    fflush(stdout);
}

谢谢!!!!

编辑 1 我添加了父变量来检查 find 函数的结果,它是 NULL,所以我遇到的第一个问题是我无法从实用程序获取容器小部件 id .

【问题讨论】:

  • 根据这个link我的方法看起来不太好,因为find只获取本地窗口ID'
  • 如果您有本地窗口 ID,请查看QWidget::createWindowContainerQWindow::fromWinId
  • 您使用的是哪个版本的 Qt?
  • 谢谢@G.M.我正在使用 Qt 5.6。我将其投入使用,但这有点棘手,而且我没有“干净”的方法来做到这一点。容器必须启动实用程序,实用程序必须创建窗口并返回 id 但不显示()窗口,然后容器用 createWindowContainer “捕获”窗口将小部件添加到 UI,最后在此之后客户端可以显示()主窗口。如果你在奇怪的事情开始发生之前这样做,比如显示两个窗口和类似的事情。我发现的唯一方法是在 show() 之前睡觉,但正如我所说,它非常脏。
  • 不太确定我是否遵循但...尝试从QWidget * 上的容器调用QWidget::show,该容器从QWidget::createWindowContainer 返回,而不是从客户端/实用程序返回。这不应该遇到任何与时间相关的问题。

标签: c++ linux qt x11


【解决方案1】:

好的。这是我过去实现的方式。

如 cmets 中所述,对于 Qt 5.x,您必须在容器中使用两个函数 QWidget::createWindowContainerQWindow::fromWinId(WId id)。但调用函数的时机也很重要,以下实现是唯一对我有用的实现,其他实现是空窗口或重复和错误的窗口。

假设容器应用程序有一个垂直布局,我将把我的嵌入式应用程序放在那个布局中。

在容器main.cpp中

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    mainContainer w;
    char cmd[1000];

    QProcess *myProcess1 = new QProcess();
    myProcess1->start("utility");
    char buff[500];
    buff[0]=0;
    myProcess1->waitForStarted();
    myProcess1->waitForReadyRead();

    myProcess1->read(buff,100);
    unsigned long long id1=atoll(buff);
    fflush(stdout);
    w.embedApps(id1);
    myProcess1->write("continue\r\n");
    w.show();
    a.exec();
    myProcess1->kill();
    return 0;
}

在mainContainer窗口中,像这样添加embedApps函数

void marinaContainer::embedApps(WId id1, WId id2)
{
    QWindow *qw = QWindow::fromWinId(id1);
    QWidget *w1= QWidget::createWindowContainer(qw,this);
    ui->verticalLayout->addWidget(w1);
}

最后在实用程序中。 main.cpp

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    utilityMainWindow w;
    printf("%lld\r\n",w.winId());
    fflush(stdout);
    char trash[100];
    //We wait until container was created and say 'ok, coninue'
    scanf("%99s",trash);
    w.show();
    return a.exec();
}

您可以使用另一种方法在父进程和子进程之间进行通信,但对于这个演示来说,这个方法就足够了。

希望对您有所帮助!享受。

【讨论】:

    【解决方案2】:

    这是一项非常复杂的任务,据我所知,没有完美的解决方案。我建议查看已经存在的东西。例如,ROS rqt 在这种思路中提供了一些东西,尽管它主要基于 PyQt,需要第三方框架(即 ROS)并且存在缺陷,尤其是在运行应用程序的进程管理方面.这是一个完整的解决方案(就我到目前为止已经设法找到的东西而言)。

    我参与了一个项目,我开发了(使用ROS rqt)一个进程监控工具(用于启动、停止和监控通过 ROS 执行的进程的状态,例如roslaunchrosrun 以及独立的应用程序)它必须从设置文件中自动生成,并且还具有进程状态恢复功能。最后一个是您可能想要使用的东西,无论您是运行后台进程还是将应用程序转换为普通小部件并将它们添加到 Qt 应用程序。它基本上是在启动“控制中心”时尽可能多地恢复进程状态。根据我正在运行的进程(当然都是自动生成的),我使用了带有一些额外信息的 PID 文件。如果您想运行已启动的外部进程而不是作为子进程(即您杀死主应用程序并杀死所有其他进程)并希望允许您的主应用程序重新获得对其在其期间启动的进程的控制,这将非常有用最后一次运行。排除这个简洁的功能,我基本上创建了一个通用界面,基于应用程序类型几乎没有衍生品,然后使用rqt 框架将它们附加到 UI。这绝对不是一件容易的事。

    为了让事情变得更简单我建议您将要“嵌入”的各种应用程序转换为自包含的QWidget(或QObject 的其他派生类)和将它们嵌入到正常的 Qt 方式中(即将小部件添加到父 QWidget)。如果您想让小部件以更自然的桌面方式移动(单击、拖动,甚至旋转),您可以在其中使用 QGraphicsSceneQGraphicsProxyWidgets。 Here is a reply 我的这个话题,下面转发了一张截图,这样你就可以了解我在说什么:

    这并不完全符合您的要求,但您仍然可以让场景中的每个代理小部件实际控制一个后台进程并公开它的一些功能。它也比您要求的要容易得多。我目前正在利用空闲时间处理图像处理应用程序的个人项目(我相信我已经在上面链接的帖子中提到了这一点)我使用这种方法,因为应用程序应该显示并允许以基于节点的方式控制事物,其中每个节点基本上都是特定类型的小部件,并提供更改数据流(如果它在视觉和逻辑级别上连接到其他产生数据的节点)。

    【讨论】:

    • 感谢@rdaleksandar,这不是理想的解决方案,但它很棒!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多