假设您确实正在尝试将子进程的 GUI 元素嵌入到您自己的进程中,那么您的代码就有一些潜在的问题。
首先,在某些平台上,可能QProcess::start
只是简单地将所需数据排队。在进入事件循环之前,子进程实际上不会分叉。因此当你有...
QProcess ps;
ps.start("sudo ./exe 1");
sleep(10);
ifstream myfile;
myfile.open("winid.txt");
WId id;
myfile >> id;
调用可能sleep(10)
只是阻止了所有内容,并且当您尝试阅读时该过程尚未开始。即使子进程确实启动了,也不能保证它会在您读取它时将其窗口 id 写入其中——而不是对信号winid.txt
采取行动要好得多。QProcess::readyReadStandardOutput
其次,您将完整的命令行传递给QProcess::start
. 在某些将通过 shell 传递命令的平台上,这意味着您必须非常小心引用/转义特殊字符。最好使用...
void QProcess::start(const QString &program, const QStringList &arguments, QIODevice::OpenMode mode = ReadWrite)
...改为重载。
最后,您在此处实际运行的命令是sudo
. 假设这是在Linux
系统(或类似系统)上,那么sudo
很可能需要密码,而您还没有设置任何提供密码的方式。
作为示例,以下代码根据调用方式执行两件事之一。
如果使用单个命令行参数调用,它会创建/显示QPushButton
派生的小部件并将该小部件的窗口 ID 写入标准输出。
如果不带参数调用,它将充当父进程。它启动了几个子进程,并且当每个子进程将其窗口 ID 打印到标准输出时,捕获相关联的小部件并将其嵌入到自己的小部件中。
#include <cstdlib>
#include <iostream>
#include <set>
#include <QApplication>
#include <QDebug>
#include <QLabel>
#include <QProcess>
#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>
#include <QWindow>
namespace {
/*
* This is the basic QPushButton derived widget that will be created by the
* child process(es).
*/
class remote_process_widget: public QPushButton {
using super = QPushButton;
public:
explicit remote_process_widget (const QString &name, QWidget *parent = nullptr)
: super(name, parent)
{
}
};
}
int
main (int argc, char **argv)
{
try {
QApplication app(argc, argv);
std::set<QProcess *> processes;
if (argc > 1) {
/*
* This process was started with at least one command line arg so we
* assume it's a managed child process. Need to write the window id to
* stdout for the parent process to read.
*/
auto *w = new remote_process_widget(QString::fromStdString(argv[1]));
w->show();
std::cout << w->winId() << std::endl;
} else {
/*
* No command line args so start up as the parent process. Create some
* child processes and set things up to manage their widgets.
*/
auto *w = new QWidget;
auto *l = new QVBoxLayout(w);
auto *label = new QLabel("Parent process");
label->setAlignment(Qt::AlignCenter);
l->addWidget(label);
w->show();
/*
* Now create/start the child processes.
*/
for (int i = 0; i < 4; ++i) {
auto *process = new QProcess;
processes.insert(process);
/*
* Connect to the `QProcess::readyReadStandardOutput` signal of the
* child. This is where the real work is done regarding the
* capture/embedding of the child processes widgets.
*/
QObject::connect(process, &QProcess::readyReadStandardOutput,
[l, process]()
{
auto wid = QString(process->readAllStandardOutput()).toULongLong();
std::cout << "wid = " << wid << "\n";
if (auto *window = QWindow::fromWinId(wid)) {
if (auto *container = QWidget::createWindowContainer(window)) {
l->addWidget(container);
}
}
});
/*
* Start the child process.
*/
process->start(argv[0], QStringList() << QString("Remote process %1").arg(i));
}
}
app.exec();
/*
* Shut down all child processes.
*/
for (auto process: processes) {
process->terminate();
std::cout << "waiting for process " << process->processId() << " to terminate\n";
while (!process->waitForFinished())
;
}
std::cout << "done\n";
}
catch (std::exception &ex) {
qCritical() << "\n" << ex.what();
}
catch (...) {
qCritical() << "\nunrecognized exception";
}
exit(0);
}
因此,虽然它不使用QML
,但如果您在没有任何参数的情况下运行它,它应该创建自己的小部件,创建四个子进程并嵌入与这些子进程关联的小部件。就像是...