Linux 在QProcess输出中保留ANSI转义序列 我正在创建一个程序,在Qt中运行QualPosits,使用Ubuntu 16.04 Qt5.5.1,其中启用了C++ 11。我将进程输出流定向到QTextEdit
我想将此输出着色,以使用本地终端通过使用嵌入的ANSI转义颜色序列解释的相同颜色。但是,我无法解析转义序列,因为QProcess输出中似乎缺少它们。我原本以为QString正在剥离它们,但经过一些测试后,我认为情况并非如此 我发现,如果我能在QProcess输出中保留转义序列,就可以为我指明ANSI转义颜色解释方向 下面是我在Qt代码中所做的一个示例项目 源文件Linux 在QProcess输出中保留ANSI转义序列 我正在创建一个程序,在Qt中运行QualPosits,使用Ubuntu 16.04 Qt5.5.1,其中启用了C++ 11。我将进程输出流定向到QTextEdit,linux,bash,qt,ansi,qprocess,Linux,Bash,Qt,Ansi,Qprocess,我想将此输出着色,以使用本地终端通过使用嵌入的ANSI转义颜色序列解释的相同颜色。但是,我无法解析转义序列,因为QProcess输出中似乎缺少它们。我原本以为QString正在剥离它们,但经过一些测试后,我认为情况并非如此 我发现,如果我能在QProcess输出中保留转义序列,就可以为我指明ANSI转义颜色解释方向 下面是我在Qt代码中所做的一个示例项目 源文件 #include "mainwindow.h" #include "ui_mainwindow.h" #include <QSt
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QString>
#include <QProcess>
#include <QStringList>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QStringList input = {"gcc will_not_build.c"};
QProcess * proc = new QProcess();
proc->setReadChannel(QProcess::StandardOutput);
proc->setProcessChannelMode(QProcess::MergedChannels);
proc->setWorkingDirectory("/path/to/test/c/file/");
//Start bash
proc->start("bash");
proc->waitForStarted();
// Write as many commands to this process as needed
foreach(QString str, input){
proc->write(str.toUtf8() + "\n");
proc->waitForBytesWritten(-1);
}
// Let bash close gracefully
proc->write("exit $?\n");
proc->waitForBytesWritten(-1);
proc->closeWriteChannel();
proc->waitForFinished();
proc->waitForReadyRead();
QByteArray read_data = proc->readAll();
// The use of tr(read_data) also works here.
QString output = tr(read_data);//QString::fromStdString (read_data.toStdString ());
proc->closeReadChannel(QProcess::StandardOutput);
proc->close();
delete proc;
// Add the output to the text box
ui->textEdit->append (output);
}
MainWindow::~MainWindow()
{
delete ui;
}
int main(){
// Intentionally will not build
I will not build :)
}
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QString>
#include <QProcess>
#include <QStringList>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QStringList input = {"unbuffer gcc will_not_build.c"};
QProcess * proc = new QProcess();
proc->setReadChannel(QProcess::StandardOutput);
proc->setProcessChannelMode(QProcess::MergedChannels);
proc->setWorkingDirectory("/path/to/test/c/file/");
//Start bash
proc->start("bash");
proc->waitForStarted();
// Write as many commands to this process as needed
foreach(QString str, input){
proc->write(str.toUtf8() + "\n");
proc->waitForBytesWritten(-1);
}
// Let bash close gracefully
proc->write("exit $?\n");
proc->waitForBytesWritten(-1);
proc->closeWriteChannel();
proc->waitForFinished();
proc->waitForReadyRead();
QByteArray read_data = proc->readAll();
// The use of tr(read_data) also works here.
QString output = tr(read_data);//QString::fromStdString (read_data.toStdString ());
proc->closeReadChannel(QProcess::StandardOutput);
proc->close();
delete proc;
// Strip default character set escape sequences, since those seem to be left
// See https://stackoverflow.com/questions/36279015/what-does-x1bb-do
output.remove("\x1b(B", Qt::CaseInsensitive);
// Since it is just one single text stream define here instead of globally
Utils::AnsiEscapeCodeHandler ansi_handler;
FormattedTextList result = ansi_handler.parseText (Utils::FormattedText(output, ui->textEdit->currentCharFormat ()));
// Loop through the text/format results
foreach(Utils::FormattedText ft, result){
ui->textEdit->setCurrentCharFormat (ft.format);
ui->textEdit->insertPlainText (ft.text);
}
}
MainWindow::~MainWindow()
{
delete ui;
}
我的输出如下所示:
QProcess gcc输出
本机Linux终端的输出如下所示:
带颜色的Linux终端gcc输出
有人知道我如何在QProcess输出中保留ANSI转义颜色序列,以便模拟Linux终端颜色吗
作为旁注,我在Qt-Creator源代码中进行了深入研究,有一个类可以将ANSI转义颜色转换为富文本颜色,因此我知道有人已经走上了这条路。同样,在构建项目时,由于某种原因,Qt Creator不会在自己的终端中为构建输出着色。
QProcess
不会干扰过程输出,只是,gcc
——就像许多其他发出彩色输出的程序一样——默认情况下,只有在检测到正在TTY设备上写入时才会发出彩色转义序列
如果要禁用此启发式并要求始终生成彩色输出,则必须将
-fddiagnostics color=always
选项添加到编译器命令行 QProcess
不会干扰进程输出,只是gcc
——就像许多其他发出彩色输出的程序一样——默认情况下,只有在检测到正在TTY设备上写入时才会发出彩色转义序列
如果要禁用此启发式并要求始终生成彩色输出,则必须将
-fddiagnostics color=always
选项添加到编译器命令行 多亏了对我问题的深刻回答,我才找到了解决问题的办法。我将分享
QProcess没有故障,QString也没有故障。问题在于程序执行的环境。由于这些程序(gcc等)的输出未连接到TTY设备,因此所有ANSI转义序列都被剥离。不过,还是有办法的
只需在命令前面加上unbuffer
因为我的使用实际上是创建一个QtCreator插件,所以我已经链接了QtCreator的大部分源代码。碰巧已经存在一个名为AnsiEscapeCodeHandler的方便类,用于将ANSI转义序列转换为相应的ANSI转义序列字符串
为了说明我是如何使用这个类的,但现在在我的示例中,我将从可下载的Qt Creator源代码中将ansiescapecodehandler.h
和ansiescapecodehandler.cpp
复制到我的测试项目中。我不得不从AnsiEscapeCodeHandler
源文件中删除几行代码,以便在Qt Creator源代码其余部分的上下文之外进行编译,但仅此而已
新的源文件
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QString>
#include <QProcess>
#include <QStringList>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QStringList input = {"gcc will_not_build.c"};
QProcess * proc = new QProcess();
proc->setReadChannel(QProcess::StandardOutput);
proc->setProcessChannelMode(QProcess::MergedChannels);
proc->setWorkingDirectory("/path/to/test/c/file/");
//Start bash
proc->start("bash");
proc->waitForStarted();
// Write as many commands to this process as needed
foreach(QString str, input){
proc->write(str.toUtf8() + "\n");
proc->waitForBytesWritten(-1);
}
// Let bash close gracefully
proc->write("exit $?\n");
proc->waitForBytesWritten(-1);
proc->closeWriteChannel();
proc->waitForFinished();
proc->waitForReadyRead();
QByteArray read_data = proc->readAll();
// The use of tr(read_data) also works here.
QString output = tr(read_data);//QString::fromStdString (read_data.toStdString ());
proc->closeReadChannel(QProcess::StandardOutput);
proc->close();
delete proc;
// Add the output to the text box
ui->textEdit->append (output);
}
MainWindow::~MainWindow()
{
delete ui;
}
int main(){
// Intentionally will not build
I will not build :)
}
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QString>
#include <QProcess>
#include <QStringList>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QStringList input = {"unbuffer gcc will_not_build.c"};
QProcess * proc = new QProcess();
proc->setReadChannel(QProcess::StandardOutput);
proc->setProcessChannelMode(QProcess::MergedChannels);
proc->setWorkingDirectory("/path/to/test/c/file/");
//Start bash
proc->start("bash");
proc->waitForStarted();
// Write as many commands to this process as needed
foreach(QString str, input){
proc->write(str.toUtf8() + "\n");
proc->waitForBytesWritten(-1);
}
// Let bash close gracefully
proc->write("exit $?\n");
proc->waitForBytesWritten(-1);
proc->closeWriteChannel();
proc->waitForFinished();
proc->waitForReadyRead();
QByteArray read_data = proc->readAll();
// The use of tr(read_data) also works here.
QString output = tr(read_data);//QString::fromStdString (read_data.toStdString ());
proc->closeReadChannel(QProcess::StandardOutput);
proc->close();
delete proc;
// Strip default character set escape sequences, since those seem to be left
// See https://stackoverflow.com/questions/36279015/what-does-x1bb-do
output.remove("\x1b(B", Qt::CaseInsensitive);
// Since it is just one single text stream define here instead of globally
Utils::AnsiEscapeCodeHandler ansi_handler;
FormattedTextList result = ansi_handler.parseText (Utils::FormattedText(output, ui->textEdit->currentCharFormat ()));
// Loop through the text/format results
foreach(Utils::FormattedText ft, result){
ui->textEdit->setCurrentCharFormat (ft.format);
ui->textEdit->insertPlainText (ft.text);
}
}
MainWindow::~MainWindow()
{
delete ui;
}
#包括“mainwindow.h”
#包括“ui_main window.h”
#包括
#包括
#包括
主窗口::主窗口(QWidget*父窗口):
QMainWindow(父级),
用户界面(新用户界面::主窗口)
{
用户界面->设置用户界面(此);
QStringList输入={“unbuffer gcc will_not_build.c”};
QProcess*proc=新的QProcess();
proc->setReadChannel(QProcess::StandardOutput);
proc->setProcessChannelMode(QProcess::MergedChannels);
proc->setWorkingDirectory(“/path/to/test/c/file/”;
//开始狂欢
proc->start(“bash”);
proc->waitForStarted();
//根据需要向该进程写入尽可能多的命令
foreach(QString str,输入){
proc->write(str.toUtf8()+“\n”);
proc->WaitForBytesWrited(-1);
}
//让bash优雅地关闭
过程->写入(“退出$?\n”);
proc->WaitForBytesWrited(-1);
proc->closeWriteChannel();
proc->waitForFinished();
proc->waitForReadyRead();
QByteArray read_data=proc->readAll();
//tr(read_data)的使用在这里也起作用。
QString output=tr(read_data);//QString::fromStdString(read_data.toStdString());
proc->closeReadChannel(QProcess::StandardOutput);
proc->close();
删除proc;
//剥离默认字符集转义序列,因为这些转义序列似乎是左转义序列
//看https://stackoverflow.com/questions/36279015/what-does-x1bb-do
output.remove(“\x1b(B”,Qt::不区分大小写);
//因为它只是一个文本流,所以在这里定义而不是全局定义
Utils::AnsiEscapeCodeHandler ansi_handler;
FormattedTextList结果=ansi_handler.parseText(Utils::FormattedText(输出,ui->textEdit->currentCharFormat());
//循环浏览文本/格式结果
foreach(Utils::FormattedText ft,结果){
用户界面->文本编辑->设置当前字符格式(ft.format);
用户界面->文本编辑->插入明文(ft.text);
}
}
MainWindow::~MainWindow()
{
删除用户界面;
}
新的头文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
// This exists in the qtcreator-src code and handles ansi escape code color parsing
#include "ansiescapecodehandler.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
typedef QList<Utils::FormattedText> FormattedTextList;
};
#endif // MAINWINDOW_H
\ifndef主窗口
#定义主窗口
#包括
//这存在于qtcreator src代码中,并处理ansi转义代码颜色解析
#包括“ansiescapecodehandler.h”
名称空间用户界面{
类主窗口;
}
类主窗口:公共QMainWindow
{
Q_对象
公众:
显式主窗口(QWidget*parent=0);
~main窗口();
私人:
Ui::MainWindow*Ui;
typedef QList FormattedTextList;
};
#endif//main窗口
新的彩色输出。。。
多亏了对我问题的深刻回答,我才能够