使用 lambda 函数了解 QProcess 信号的行为
Posted
技术标签:
【中文标题】使用 lambda 函数了解 QProcess 信号的行为【英文标题】:Understanding behaviour of QProcess signals with a lambda function 【发布时间】:2016-03-29 16:29:01 【问题描述】:这是 Qt 5.4.0 中的一个问题。并已在 Qt 5.6.0 中修复
我有一个允许用户使用QProcess
启动进程的应用程序。
最初我想将QProcess::finished
信号连接到一个 lambda 函数,但由于它是一个重载函数,由于连接哪个函数不明确,似乎无法完成。
因此,我尝试了监控QProcess
的状态变化。
void MainWindow::on_actionLaunchApplication_triggered()
// launch the file open dialog for the user to select a file
QString filePath = QFileDialog::getOpenFileName(this, "Select Application to Launch", "/Applications");
if(filePath == "")
return;
QProcess* proc = new QProcess(this);
// can't connect to QProcess::exited with lambda, due to its overloaded function, so will check state changed instead
connect(proc, &QProcess::stateChanged, [filePath, proc, this](QProcess::ProcessState state)
if(state == QProcess::NotRunning)
qDebug << "Deleting proc";
disconnect(proc, &QProcess::stateChanged, 0 , 0);
proc->deleteLater();
);
proc->start(filePath);
通常这会按预期工作;选择的应用程序被执行,并且可以选择不同的应用程序以这种方式一个接一个地运行。退出这样的应用程序会导致执行删除 QProcess 的 tidyup 代码。
但是,如果已使用 QProcess 启动的应用程序退出,然后再次选择执行,则它无法启动,而是立即从 lambda 函数中对 deleteLater
的调用中删除该进程。
那么,发生了什么?考虑到每次都会创建一个新的QProcess,为什么每个应用程序都是第一次工作,但如果这样的应用程序退出并选择再次启动,它会立即被删除?
我完全清楚我可以在没有 lambda 函数或通过 SIGNAL 和 SLOT 宏的情况下连接到 QProcess::finished
。这个问题是学术性的,我正在寻找对这里发生的事情的理解。
到目前为止,响应答案和 cmets,看起来这是一个 Qt 错误。连接到QProcess::finished
插槽会导致相同的问题,即仅在第一次启动应用程序。
// launch the file open dialog for the user to select a file
QString filePath = QFileDialog::getOpenFileName(this, "Select Application to Launch", "/Applications");
if(filePath == "")
return;
QProcess* proc = new QProcess();
connect(proc, static_cast<void (QProcess::*)(int)>(&QProcess::finished), [filePath, proc, this](int exitStatus)
Q_UNUSED(exitStatus);
Log("Deleting proc for launched app");
proc->deleteLater();
proc->disconnect(proc, static_cast<void (QProcess::*)(int)>(&QProcess::finished), 0, 0);
);
proc->start(filePath);
【问题讨论】:
你能在start
之后测试proc
的状态吗?可能第二次不在同一个初始状态。
现在当您说QProcess::exited
时,您的意思是QProcess::finished
,对吗?如果是这样,文档显示了如何使用函数指针语法连接到它的示例。
@thuga 是的,你是对的,它是 QProcess::finished
。感谢您指出这一点。
@thuga,更新到 Qt 5.6.0 解决了这个问题。
这很有趣。想知道他们改变了什么。
【参考方案1】:
其实可以连接信号!您所要做的就是告诉编译器它应该选择哪个信号,因为它无法决定这一点。
这个问题有一个很好的答案:Qt5 overloaded Signals and Slots。
这不会解决您的奇怪删除行为问题,但也许问题会通过这种方式自行解决。
【讨论】:
谢谢@Felix,知道这真的很有用。有趣的是,它并没有解决问题,并且尝试第二次启动相同的应用程序无法启动。我开始认为这是 Qt 的内部问题。【参考方案2】:finished
信号表示状态转换。但相反,您检查的是静态状态,而不是转换。
你应该保留一个与进程相关的属性来指示它正在运行或正在启动,然后只有在它停止运行或启动失败时才删除该进程。
void MainWindow::on_actionLaunchApplication_triggered()
auto locations = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation);
if (locations.isEmpty())
locations << QString();
auto filePath = QFileDialog::getOpenFileName(this, "Select Application to Launch",
locations.first());
if (filePath.isEmpty())
return;
bool wasActive = false; // upon capture, it becomes a per-process field
auto proc = new QProcess(this);
connect(proc, &QProcess::stateChanged, [=](QProcess::ProcessState state) mutable
if (state == QProcess::Running)
qDebug() << "Process" << proc << "is running";
wasActive = true;
else if (state == QProcess::Starting)
qDebug() << "Process" << proc << "is starting";
wasActive = true;
else if (state == QProcess::NotRunning && wasActive)
qDebug() << "Will delete a formerly active process" << proc;
proc->deleteLater();
else /* if (state == QProcess::NotRunning) */
qDebug() << "Ignoring a non-running process" << proc;
);
proc->start(filePath);
【讨论】:
谢谢 Kuba,我尝试过类似的方法,但无论是这样,你的代码也不起作用;同样的情况是,第二次启动应用程序会首先导致QProcess::NotRunning
的状态并退出。相反,第一次启动应用程序时,它会进入QProcess::Starting
,然后是QProcess::Running
,最后在退出时调用QProcess::NotRunning
。因此,即使实例化了新的 QProcess,我仍然不知道为什么第二次状态会有所不同。
@TheDarkKnight 我不知道您是否使用 Qt 5.6,但如果您使用的是,它会发出 errorOccurred
信号吗?
@thuga,我目前正在使用 5.4,但现在正在下载 5.6,并会报告。
问题在 Qt 5.6.0 中得到解决。谢谢大家的讨论。以上是关于使用 lambda 函数了解 QProcess 信号的行为的主要内容,如果未能解决你的问题,请参考以下文章