您的位置:首页 > 运维架构 > Shell

用Qt实现一个简单的shell (Qt5+V8)

2013-08-01 10:39 453 查看
在CSDN论坛看到有网友问用Qt如何实现一个类似shell的东西。

同时呢,前两天V8已经成为Qt5的基础模块了,刚好,可以做个简单的javascript的shell试试看(只支持单行输入)。

于是,便有了本文。


何处着手?

先用google搜索一下,未找到自己想要的答案(当然,有些比较靠谱的答案:比如去看现有shell(像konsole等)的源码,只是自己懒,不想看)。

初看起来,似乎是个比较简单的东西。
用一个只读的控件来显示输入和输出
用一个输入控件来接受输入

按照这个思路,加上对shell的期望:
选择只读的 QPlainTextEdit 作为主控件
用一个 QLineEdit 接受输入

于是:就是下面的效果了,







注意

前两个图,是在Qt5下的结果。(你可以访问V8
初次接触(Qt5)来了解Qt5和V8的关系)

第三个图,是Qt4下编译后的结果(没有V8的参与)。


难点?

在贴出源码之前,先提一点这个:

每次等待输入时,都要有提示符,比如">>> "

我们只需要将QLineEdit定位到">>>"这个位置即可

但是,获取这个位置有些困难,为此,动用了 QPlainTextEditPrivate 这个私有类!


源码

分为三个文件
shelldemo.h
shelldemo.cpp
main.cpp


shelldemo.h

创建QPlainTextEdit的派生类
runCommand() 将输入的命令进行处理,而后输出
onEditFinished() 响应输出完时的回车
onScrollBarValueChanged() 滚动条变动时,我们要调整QLineEdit的位置
resizeEvent() 窗口变化时,我们也要调整QLineEdit的大小和位置

[cpp] view
plaincopy

#ifndef SHELLDEMO_H  

#define SHELLDEMO_H  

  

#include <QPlainTextEdit>  

  

class QLineEdit;  

class ShellDemo:public QPlainTextEdit  

{  

    Q_OBJECT  

public:  

    explicit ShellDemo(QWidget *parent=0);  

    virtual QString runCommand(const QString& cmd);  

protected:  

    void resizeEvent(QResizeEvent *e);  

private slots:  

    void onScrollBarValueChanged();  

    void onEditFinished();  

private:  

    void updateEditPosition();  

    QLineEdit * edit;  

};  

  

#endif // SHELLDEMO_H  


shelldemo.cpp

这个是重点了,你可以忽略其中关于Qt5和V8的代码(已经被宏保住了,不会影响你的编译)。

[cpp] view
plaincopy

#include "shelldemo.h"  

#include <QLineEdit>  

#include <QTextBlock>  

#include <QDebug>  

#include <private/qplaintextedit_p.h>  

  

#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)  

#include <private/v8.h>  

#endif  

  

ShellDemo::ShellDemo(QWidget *parent) :  

    QPlainTextEdit(parent)  

{  

    setReadOnly(true);  

  

    QFont font = this->font();  

    font.setPointSize(font.pointSize()+2);  

    this->setFont(font);  

  

    appendPlainText(">>> ");  

    edit = new QLineEdit(this->viewport());  

    edit->setStyleSheet("border-style:none; background-color:transparent;");  

  

    connect(edit, SIGNAL(returnPressed()), SLOT(onEditFinished()));  

    connect(verticalScrollBar(), SIGNAL(valueChanged(int)), SLOT(onScrollBarValueChanged()));  

}  

  

void ShellDemo::resizeEvent(QResizeEvent *e)  

{  

    updateEditPosition();  

}  

  

void ShellDemo::onScrollBarValueChanged()  

{  

    updateEditPosition();  

}  

  

QString ShellDemo::runCommand(const QString &cmd)  

{  

#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)  

    QString output;  

    v8::HandleScope handle_scope;  

    v8::Persistent<v8::Context> context = v8::Context::New();  

    v8::Context::Scope context_scope(context);  

    v8::Handle<v8::String> source = v8::String::New(cmd.utf16());  

    v8::TryCatch try_catch;  

    v8::Handle<v8::Script> script = v8::Script::Compile(source);  

    if (script.IsEmpty()) {  

        output = QString::fromUtf16(*(v8::String::Value(try_catch.Exception())));  

    } else {  

        v8::Handle<v8::Value> result = script->Run();  

        if (result.IsEmpty()) {  

            output = QString::fromUtf16(*(v8::String::Value(try_catch.Exception())));  

        } else {  

            output = QString::fromUtf16(*(v8::String::Value(result)));  

        }  

    }  

    context.Dispose();  

    return output;  

#else  

    return QString("Result of %1").arg(cmd);  

#endif  

}  

  

void ShellDemo::onEditFinished()  

{  

    QString cmd = edit->text();  

    if (cmd.isEmpty()) {  

        return;  

    }  

    moveCursor(QTextCursor::End);  

    insertPlainText(cmd);  

    edit->hide();  

    edit->clear();  

  

    appendPlainText(runCommand(cmd));  

  

    appendPlainText(">>> ");  

    updateEditPosition();  

    edit->show();  

    edit->setFocus();  

}  

  

void ShellDemo::updateEditPosition()  

{  

    QPlainTextEditPrivate * d = reinterpret_cast<QPlainTextEditPrivate*>(qGetPtrHelper(d_ptr));  

    QRectF rect = d->control->blockBoundingRect(d->control->document()->lastBlock());  

    edit->move(rect.topRight().toPoint());  

    edit->resize(viewport()->size().width(), edit->size().height());  

}  

简单说一下:
updateEditPosition()

用来更新QLineEdit的位置(这里面的代码?你凑活看吧,其实代码还有些问题)。

ShellDemo() 构造函数

基本没做什么。上面设置了大两个点的字体,纯粹是为了舒服一点(不然在我机子上比较难看)。QLineEdit隐藏掉边框,以便和主控件融为一体。
runCommand()

根据输入,产生什么输出,你说了算。我只是为了学习下V8,胡乱加了点代码。
onEditFinished()

将输入输出显示到主控件中。


main.cpp

很常规的文件,不用多说。

[cpp] view
plaincopy

#include <QtGui/QtGui>  

#include "shelldemo.h"  

  

int main(int argc, char *argv[])  

{  

    QApplication a(argc, argv);  

  

    ShellDemo w;  

    w.setWindowTitle("Dbzhang800\'s Qt5 V8-Shell");  

    w.show();  

  

    return a.exec();  

}  


qt5v8.pro

.pro 文件很简单,对于Qt5,我们使用了v8模块

contains(QT_VERSION, ^5\\..*\\..*) {
QT  += v8-private gui-private core-private
}
SOURCES += main.cpp \
shelldemo.cpp
HEADERS += \
shelldemo.h \
shellodemo_p.h



后记

本例子功能非常不完善,仅供参考
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: