在qt application

时间:2016-10-31 18:13:25

标签: c++ linux qt x11

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

允许调用应用程序容器容器和执行容器实用程序

的容器

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

我想在utility1Widget中看到实用程序的GUI。

Edit2 :最初的方法是错误的,我将它放在这里以供将来参考,但是我的工作实现在我的分离答案中。

我尝试没有成功获取实用工具1Widget的WId并在实用程序的开始时将其作为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

2 个答案:

答案 0 :(得分:3)

确定。这是我过去常常实现的方式。

如评论中所述,对于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();
}

您可以使用其他方法在父进程和子进程之间进行通信,但这个方法足以用于此演示。

希望它有所帮助!请享用。

答案 1 :(得分:0)

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

我参与了一个项目,我开发了一个项目(使用ROS rqt)一个流程监控工具(用于启动,停止和监控通过ROS执行的流程状态,例如roslaunch或{{1}还有独立的应用程序),它们必须从设置文件自动生成,并且还具有进程状态恢复功能。无论您是运行后台进程还是将应用程序转换为普通小部件并将其添加到Qt应用程序,最后都可以使用。它基本上是在启动“控制中心”时尽可能地恢复过程的状态。我根据我正在运行的进程使用了​​PID文件和一些额外的信息(当然都是自动生成的)。如果您希望运行已启动的外部进程而不是作为子进程(即您终止主应用程序并且所有其他进程都被终止)并且希望允许主应用程序重新控制其在其中启动的进程,则此功能非常有用最后一次。除了这个简洁的功能,我基本上创建了一个基于应用程序类型的小衍生物的通用接口,然后使用rosrun框架将它们附加到UI。这绝对不是一件容易的事。

为了简化操作,我建议您将要嵌入的各种应用程序转换为自包含的rqt(或{{1}的其他衍生产品})类并以正常的Qt方式嵌入(即将小部件添加到父QWidget)。如果您想让窗口小部件以更自然的桌面方式移动(单击,拖动,甚至旋转),您可以使用QObject并使用QWidget。关于这个主题我的Here is a reply,其中一个屏幕截图在下面重新发布,以便您可以了解我在说什么:

enter image description here

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