功能描述:开发一个类似于 Windows 命令行提示符或 Linux 命令行终端的应用程序
一、最终演示效果
QtCmd 不是因为它是 Qt 的组件,而是采用 Qt 开发了一个类似 Windows 命令提示符或者 Linux 命令行终端的应用程序,故取名为 QtCmd。
上述演示是在 Win10 操作系统下,模拟命令提示符的功能,输入错误的指令(如 windows 下输入 ls 指令),错误输出的字体颜色为红色;输入正确的指令(如 windows 下输入dir 指令),标准输出的字体颜色显示正常。
本应用程序原为一个项目的子功能,实现命令行终端的界面,现把这一功能单独封装了一个窗体类,分享给大家参考,可以直接集成到你的应用程序中。
具体功能使用就不多说了,和命令行终端的功能一模一样,只是说把这一功能集成到自己的应用程序中了,命令行终端支持的指令,本终端全部支持。
二、命令行终端程序开发
命令行终端程序主要在 terminalwidget.h 和 terminalwidget.cpp 中封装了 TerminalWidget 类,实现了有关命令输入和信息输出的所有功能。
terminalwidget.h 文件代码如下:
#ifndef TERMINALWIDGET_H
#define TERMINALWIDGET_H
#include <QTextEdit>
#include <QKeyEvent>
#include <QFont>
#include <QProcess>
#include <QByteArray>
#include <QLabel>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QTextLayout>
#include <QTextCursor>
#include <QTextBlock>
#include <QTextCodec>
#include <assert.h>
class TerminalWidget: public QTextEdit
{
Q_OBJECT
public:
TerminalWidget();
protected:
void keyPressEvent(QKeyEvent *e);
private:
// 字体
QFont font;
// 命令行终端进程
QProcess * proc;
// 光标位置
long long lastPosition = 0;
// 上一次的输入内容
QByteArray lastInput;
public slots:
/**
* @brief readyReadStandardOutputSlot 标准输出
*/
void readyReadStandardOutputSlot();
/**
* @brief readyReadStandardErrorSlot 错误输出
*/
void readyReadStandardErrorSlot();
};
#endif // TERMINALWIDGET_H
terminalwidget.cpp 文件代码如下:
#include "terminalwidget.h"
#include <QDebug>
TerminalWidget::TerminalWidget()
{
setStyleSheet("background-color:rgb(0,0,0); color:rgb(255,255,255); border:0px;");
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
resize(1000,700);
setWindowTitle("命令行提示符");
font.setFamily("Times New Roman");
font.setPixelSize(14);
setFont(font);
proc = new QProcess();
connect(proc,SIGNAL(readyReadStandardOutput()),this,SLOT(readyReadStandardOutputSlot()));
connect(proc,SIGNAL(readyReadStandardError()),this,SLOT(readyReadStandardErrorSlot()));
#ifdef Q_OS_WIN
proc->start("cmd");
#elif Q_OS_LINUX
proc->start("bash");
#endif
QTextCursor editCursor = textCursor();
QTextBlockFormat textBlockFormat;
textBlockFormat.setLineHeight(20, QTextBlockFormat::FixedHeight);
editCursor.setBlockFormat(textBlockFormat);
setTextCursor(editCursor);
}
void TerminalWidget::keyPressEvent(QKeyEvent *e)
{
QTextCursor editCursor = textCursor();
// Qt::Key_Enter 是小键盘(数字键盘)的 Enter,对应的虚拟键码为:0x01000005
// Qt::Key_Return 是大键盘区的 Enter,对应的虚拟键码为:0x01000004
if(e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter)
{
e->ignore();
editCursor.setPosition(lastPosition, QTextCursor::MoveAnchor);
editCursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
QString string = editCursor.selectedText();
editCursor.clearSelection();
#ifdef Q_OS_WIN
lastInput = string.toLocal8Bit() + '\r' + '\n';
#elif Q_OS_LINUX
lastInput = string.toLocal8Bit() + '\n';
#endif
proc->write(lastInput);
return;
}
else if(e->key() == Qt::Key_Backspace && editCursor.position() <= lastPosition)
return;
else if(e->key() == Qt::Key_Delete && editCursor.position() <= lastPosition)
return;
else
return QTextEdit::keyPressEvent(e);
}
void TerminalWidget::readyReadStandardOutputSlot()
{
QByteArray ba = proc->readAllStandardOutput();
QTextCodec * textCodec = QTextCodec::codecForName("System");
// assert 断言,如果 textCodec 为空,则编译报错
assert(textCodec != nullptr);
QString output = textCodec->toUnicode(ba);
if (output.length() > 0 && output != QString::fromLocal8Bit(lastInput))
{
setTextColor(Qt::white);
append(output.trimmed());
moveCursor(QTextCursor::End);
lastPosition = textCursor().position();
}
}
void TerminalWidget::readyReadStandardErrorSlot()
{
QByteArray ba = proc->readAllStandardError();
QTextCodec* textCodec = QTextCodec::codecForName("System");
// assert 断言,如果 textCodec 为空,则编译报错
assert(textCodec != nullptr);
QString output = textCodec->toUnicode(ba);
if (output.length() > 0 && output != QString::fromLocal8Bit(lastInput))
{
setTextColor(Qt::red);
append(output.trimmed());
moveCursor(QTextCursor::End);
lastPosition = textCursor().position();
}
}
完整的代码已经贴上,每个函数的备注写的非常清楚,如有不清楚的地方可以私信我。
如果出现中文乱码的问题,请参考我的另外一篇博客《第十课:Qt 字符编码和中文乱码相关问题》 ,百分百能解决你的问题!