使用lambda函数

时间:2016-03-29 16:29:02

标签: macos qt lambda

这是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);

2 个答案:

答案 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);
}