这是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的整理代码。
但是,如果已使用QProcess启动的应用程序退出然后再次选择执行,则无法启动,而是在lambda函数中调用deleteLater
时立即删除该进程。
那么,发生了什么?考虑到每次都会创建一个新的QProcess,为什么它会在第一次为每个应用程序工作,但如果这样的应用程序退出并选择再次启动,它会立即被删除?
我完全清楚我可以在没有lambda函数或SIGNAL和SLOT宏的情况下连接到QProcess::finished
。这个问题是学术性的,我正在寻找对这里发生的事情的理解。
到目前为止对答案和评论的回答,看起来这是一个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);
答案 0 :(得分:2)
事实上,你可以连接到信号!您所要做的就是告诉编译器应该选择哪个信号,因为它无法做出决定。
在这个问题中对这个问题有很好的回答:Qt5 overloaded Signals and Slots。
这不会解决您的奇怪删除行为问题,但问题可能会解决这个问题。
答案 1 :(得分:1)
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);
}