在 qt 应用程序中执行 qt 应用程序
Executing a qt application inside qt application
我正在尝试将几个 qt 应用程序嵌入到另一个仅用作容器的应用程序中。 (我正在使用 linux)
让我们调用应用程序容器 container 和一个执行的表单容器 utility
在 容器 中,我有一个 QTabWidget,在这个 QTabWidget 中,我有一个带有名为 utility1Widget 的小部件的选项卡。
我想查看 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 我添加了 parent 变量来检查 find 函数的结果,它是 NULL,所以我遇到的第一个问题是我无法获取容器小部件 ID,来自实用程序。
这是一项非常复杂的任务,据我所知没有完美的解决方案。我建议看看已经存在的东西。例如,ROS rqt 提供了一些符合这种思路的东西,尽管它主要基于 PyQt,需要第三方框架(即 - ROS)并且存在错误,尤其是在流程方面运行ning 应用程序的管理。这是一个完整的解决方案(据我到目前为止设法找到的东西)。
我在一个项目中开发(使用 ROS rqt
)一个进程监控工具(用于启动、停止和监控通过 ROS 执行的进程的状态,例如 roslaunch
或 rosrun
以及独立应用程序)必须从设置文件自动生成并且还具有进程状态恢复功能。最后一个是您可能想要使用的东西,无论您是 运行 后台进程还是将您的应用程序转换为普通小部件并将它们添加到 Qt 应用程序。它基本上是在启动 "control center" 时尽可能多地恢复进程状态。我使用了 PID 文件,每个文件都有一些额外的信息,具体取决于我 运行ning 的过程(当然都是自动生成的)。如果您希望 运行 启动的外部进程不是子进程(即您杀死主应用程序并且所有其他进程都被杀死)并且希望允许您的主应用程序重新控制它的进程,这将很有用已在其最后 运行 期间开始。除了这个简洁的功能,我基本上创建了一个基于应用程序类型的小派生的通用接口,然后使用 rqt
框架将它们附加到 UI。这绝对不是一件容易的事。
为了让事情更简单我建议你把你想要的各种应用程序"embed"转换成独立的QWidget
(或者一些QObject
) 类 的其他派生并将它们嵌入到正常的 Qt 方式中(即将小部件添加到父级 QWidget
)。如果您想让小部件以更自然的桌面方式移动(单击、拖动、甚至旋转),您可以使用 QGraphicsScene
和 QGraphicsProxyWidget
。我的 Here is a reply 关于此主题的其中一个屏幕截图重新 post 下面,以便您可以了解我在说什么:
这不是您要找的东西,但您仍然可以使场景中的每个代理小部件实际控制后台进程并公开其某些功能。它也比你要求的要容易得多。我目前正在利用空闲时间在一个图像处理应用程序上进行个人项目(我相信我已经在上面链接的 post 中提到了这一点),我在其中使用了这种方法,因为该应用程序应该以基于节点的方式显示并允许控制事物,其中每个节点基本上都是特定类型的小部件,并提供改变数据流的功能(如果它在视觉上和逻辑层面上都连接到产生数据的其他节点)。
好的。这是我曾经实现的方式。
如评论中所述,对于 Qt 5.x,您必须在容器中使用两个函数 QWidget::createWindowContainer and QWindow::fromWinId(WId id)。但调用函数的时机也很重要,下面的实现是唯一对我有用的实现,其他实现为空 windows 或重复和错误 windows.
假设在容器应用程序中有一个垂直布局,我将把我的嵌入式应用程序放在那个布局中。
容器中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 window 中,像这样添加 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();
}
您可以使用另一种方法在父进程和子进程之间进行通信,但对于本演示来说,这种方法已经足够了。
希望对您有所帮助!享受。
我正在尝试将几个 qt 应用程序嵌入到另一个仅用作容器的应用程序中。 (我正在使用 linux)
让我们调用应用程序容器 container 和一个执行的表单容器 utility
在 容器 中,我有一个 QTabWidget,在这个 QTabWidget 中,我有一个带有名为 utility1Widget 的小部件的选项卡。
我想查看 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 我添加了 parent 变量来检查 find 函数的结果,它是 NULL,所以我遇到的第一个问题是我无法获取容器小部件 ID,来自实用程序。
这是一项非常复杂的任务,据我所知没有完美的解决方案。我建议看看已经存在的东西。例如,ROS rqt 提供了一些符合这种思路的东西,尽管它主要基于 PyQt,需要第三方框架(即 - ROS)并且存在错误,尤其是在流程方面运行ning 应用程序的管理。这是一个完整的解决方案(据我到目前为止设法找到的东西)。
我在一个项目中开发(使用 ROS rqt
)一个进程监控工具(用于启动、停止和监控通过 ROS 执行的进程的状态,例如 roslaunch
或 rosrun
以及独立应用程序)必须从设置文件自动生成并且还具有进程状态恢复功能。最后一个是您可能想要使用的东西,无论您是 运行 后台进程还是将您的应用程序转换为普通小部件并将它们添加到 Qt 应用程序。它基本上是在启动 "control center" 时尽可能多地恢复进程状态。我使用了 PID 文件,每个文件都有一些额外的信息,具体取决于我 运行ning 的过程(当然都是自动生成的)。如果您希望 运行 启动的外部进程不是子进程(即您杀死主应用程序并且所有其他进程都被杀死)并且希望允许您的主应用程序重新控制它的进程,这将很有用已在其最后 运行 期间开始。除了这个简洁的功能,我基本上创建了一个基于应用程序类型的小派生的通用接口,然后使用 rqt
框架将它们附加到 UI。这绝对不是一件容易的事。
为了让事情更简单我建议你把你想要的各种应用程序"embed"转换成独立的QWidget
(或者一些QObject
) 类 的其他派生并将它们嵌入到正常的 Qt 方式中(即将小部件添加到父级 QWidget
)。如果您想让小部件以更自然的桌面方式移动(单击、拖动、甚至旋转),您可以使用 QGraphicsScene
和 QGraphicsProxyWidget
。我的 Here is a reply 关于此主题的其中一个屏幕截图重新 post 下面,以便您可以了解我在说什么:
这不是您要找的东西,但您仍然可以使场景中的每个代理小部件实际控制后台进程并公开其某些功能。它也比你要求的要容易得多。我目前正在利用空闲时间在一个图像处理应用程序上进行个人项目(我相信我已经在上面链接的 post 中提到了这一点),我在其中使用了这种方法,因为该应用程序应该以基于节点的方式显示并允许控制事物,其中每个节点基本上都是特定类型的小部件,并提供改变数据流的功能(如果它在视觉上和逻辑层面上都连接到产生数据的其他节点)。
好的。这是我曾经实现的方式。
如评论中所述,对于 Qt 5.x,您必须在容器中使用两个函数 QWidget::createWindowContainer and QWindow::fromWinId(WId id)。但调用函数的时机也很重要,下面的实现是唯一对我有用的实现,其他实现为空 windows 或重复和错误 windows.
假设在容器应用程序中有一个垂直布局,我将把我的嵌入式应用程序放在那个布局中。
容器中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 window 中,像这样添加 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();
}
您可以使用另一种方法在父进程和子进程之间进行通信,但对于本演示来说,这种方法已经足够了。
希望对您有所帮助!享受。