我是Qt的初学者。我需要从桌面应用程序中的按钮调用命令行程序。该计划下载YouTube视频。我还需要从中读取标准错误。我写了以下代码:
void YoutubeDL::on_downloadButton_clicked()
{
[...]
QProcess p;
p.startDetached("youtube-dl -f " + get + " " + ui->urlBox->text());
QString perr = p.readAllStandardError();
if (perr.length())
ui->descBox->setText("Error during download.\n" + perr);
else
ui->descBox->setText("Download completed!");
}
然而,stderr读取不会发生。
另一方面,如果我使用非分离p.start()
然后waitForFinished(-1)
,那么我可以读取stderr,但GUI会冻结,直到下载完成。
如何解决这个问题?
一个相关的问题:我还想要一些方法能够实时读取下载过程的输出,以便我可以在GUI中显示它。 youtube-dl给出了这样的进度报告:
[download] 0.0% of 2.00MiB at 173.22KiB/s ETA 00:12
[download] 0.1% of 2.00MiB at 105.01KiB/s ETA 00:19
[download] 0.3% of 2.00MiB at 96.86KiB/s ETA 00:21
[download] 0.7% of 2.00MiB at 105.23KiB/s ETA 00:19
[download] 1.5% of 2.00MiB at 100.29KiB/s ETA 00:20
...
我希望能够在生成它们时阅读这些内容。
答案 0 :(得分:5)
由于问题的性质,上述所有答案都不正确。 @aakashjain要求分离进程。你们建议的仅适用于启动过程仍然附加的情况。
QProcess p
p.startDetached(...)
与
相同QProcess::startDetached(...)
QProcess :: startDetached()是一个静态方法,它不是任何对象的一部分或返回一个。一旦调用此方法并且成功,该过程将不再以任何方式附加到生成它的过程(您的应用程序)。
我建议你先查看official documentation on this method,然后阅读更多关于interprocess communication以及如何将一个进程的输出传递给另一个进程(在这种情况下是对终端的分离进程)。
我偶然发现了在PyQt4中使用 QProcess :: startDetached()进行基本控制的问题,其中我做了@DmitrySokolov建议的内容。令我惊讶的是,状态始终为零,使用QProcess非静态方法无法设置或检索任何内容。在进行了一些挖掘和询问后,我确切地指出了我在答案开始时所写的内容 - 如果使用 QProcess :: startDetached(),则后面的控件必须通过系统工具(例如 kill 命令,管道等),因为你没有可以实际使用的对象。
QProcess :: startDetached()提供两个重要的返回值:
您可以使用此PID与您喜欢的过程进行交互(当然,过程本身也允许您这样做)) - 您可以终止它,管道输出,让它进入睡眠状态等。
现在回到你的问题。这里有三种解决方案:
ui->descBox
中输出进度(您还可以添加QProgressbar以使输出更加用户友好并执行标准输出/ stderr在后台的东西只为你看)。我没有对此进行测试,但实际上它应该可行。答案 1 :(得分:2)
在开始流程之前,将QProcess
信号连接到您的广告位:
void finished(int exitCode, QProcess::ExitStatus exitStatus)
void readyReadStandardError()
void readyReadStandardOutput()
当finished()
信号被触发时,您可以使用sdterr
方法读取所有readAllStandardError()
输出,或者当stderr
为readyReadStandardError()
时,您可以阅读部分youtube-dl
数据触发。
据我了解,stdout
将进度数据输出到readyReadStandardOutput
。因此,您可以在触发class YoutubeDL
{
...
private:
QProcess p;
void on_process_finished(int exitCode, QProcess::ExitStatus exitStatus);
void on_process_readyReadStandardOutput();
};
void YoutubeDL::on_downloadButton_clicked()
{
...
p.connect(&p, &QProcess::readyReadStandardOutput,
this, &YoutubeDL::on_process_readyReadStandardOutput);
p.connect(&p, (void (QProcess::*)(int,QProcess::ExitStatus))&QProcess::finished,
this, &YoutubeDL::on_process_finished);
p.start("youtube-dl -f " + get + " " + ui->urlBox->text());
}
void YoutubeDL::on_process_finished(int exitCode, QProcess::ExitStatus exitStatus)
{
QString perr = p.readAllStandardError();
if (perr.length())
ui->descBox->setText("Error during download.\n" + perr);
else
ui->descBox->setText("Download completed!");
}
void YoutubeDL::on_process_readyReadStandardOutput()
{
p.setReadChannel(QProcess::StandardOutput);
QTextStream stream(&p);
while (!stream.atEnd()) {
QString line = stream.readLine();
// extract progress info from line and etc.
...
}
}
信号时阅读并解析。
<强>更新强>
{{1}}
答案 2 :(得分:1)
不要等完了。而不是使用QProcess信号readyReadStandardError通知您可以读取任何内容。