Tay*_*510 7 javascript c++ qt interpreter read-eval-print-loop
默认print()功能QScriptEngine将结果打印到Qt Creator IDE的终端以进行调试.因此,如果我们要自己制作ECMA脚本解释器,则必须将输出重定向到我们的texteditor.
自Qt 4.3以来,文档" 使应用程序可编写脚本 "的这一部分保持不变.
Qt Script提供了一个内置的print()函数,可用于简单的调试.内置的print()函数写入标准输出.您可以重新定义print()函数(或添加您自己的函数,例如debug()或log()),将文本重定向到其他位置.以下代码显示了一个自定义print(),它将文本添加到QPlainTextEdit.
所以这是建议的重新定义print():
QScriptValue QtPrintFunction(QScriptContext *context, QScriptEngine *engine)
{
QString result;
for (int i = 0; i < context->argumentCount(); ++i) {
if (i > 0)
result.append(" ");
result.append(context->argument(i).toString());
}
QScriptValue calleeData = context->callee().data();
QPlainTextEdit *edit = qobject_cast<QPlainTextEdit*>(calleeData.toQObject());
edit->appendPlainText(result);
return engine->undefinedValue();
}
Run Code Online (Sandbox Code Playgroud)
起初,我怀疑是否需要返回"Undefined Value" return engine->undefinedValue();,看起来参数的作用*engine就是返回这个void值.
所以这就是我改变功能的方法:
QScriptValue myPrintFunction(QScriptContext *context, QScriptEngine *engine)
{
QString result;
for (int i = 0; i < context->argumentCount(); ++i) {
if (i > 0)
result.append(" ");
result.append(context->argument(i).toString());
}
/*
QScriptValue calleeData = context->callee().data();
QPlainTextEdit *edit = qobject_cast<QPlainTextEdit*>(calleeData.toQObject());
edit->appendPlainText(result);
return engine->undefinedValue();
*/
return engine->toScriptValue(result); // ---> return the result directly
}
Run Code Online (Sandbox Code Playgroud)
我认为对我来说更合理:QScriptValue从脚本引擎返回一个评估值,稍后可以将该值转换QString为输出值.这绕过了动态类型转换的需要,特别是对于自定义QObject,它可能变得混乱.
对于这两种打印功能,这里是脚本引擎的说明:
QScriptEngine *engine = new QScriptEngine(this);
QTextEdit *input = new QTextEdit(this);
QTextEdit *output = new QTextEdit(this);
// Use documented print function :
QScriptValue fun = engine->newFunction(QtPrintFunction);
// Use my revised print function :
// QScriptValue fun = engine->newFunction(myPrintFunction);
fun.setData(engine->newQObject(output));
engine->globalObject().setProperty("print", fun);
Run Code Online (Sandbox Code Playgroud)
评估和输出:
QString command = input->toPlainText();
QScriptValue result = engine->evaluate(command);
output->append(result.toString());
Run Code Online (Sandbox Code Playgroud)
(需要Qt版本> 4)
test.pro
QT += core gui widgets script
TARGET = Test
TEMPLATE = app
SOURCES += main.cpp\
console.cpp
HEADERS += console.hRun Code Online (Sandbox Code Playgroud)
main.cpp中
#include <QApplication>
#include "console.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Console w;
w.show();
return app.exec();
}Run Code Online (Sandbox Code Playgroud)
console.h
#ifndef CONSOLE_H
#define CONSOLE_H
#include <QWidget>
#include <QVBoxLayout>
#include <QTextEdit>
#include <QPushButton>
#include <QScriptEngine>
class Console : public QWidget
{
Q_OBJECT
public:
Console();
~Console();
public slots:
void runScript();
private:
QScriptEngine *engine;
QVBoxLayout *layout;
QPushButton *run;
QTextEdit *input, *output;
};
QScriptValue QtPrintFunction(QScriptContext *context, QScriptEngine *engine);
QScriptValue myPrintFunction(QScriptContext *context, QScriptEngine *engine);
#endif // CONSOLE_HRun Code Online (Sandbox Code Playgroud)
console.cpp
#include "console.h"
Console::Console()
{
engine = new QScriptEngine(this);
layout = new QVBoxLayout(this);
run = new QPushButton("Run",this);
input = new QTextEdit(this);
output = new QTextEdit(this);
layout->addWidget(input);
layout->addWidget(run);
layout->addWidget(output);
//QScriptValue fun = engine->newFunction(QtPrintFunction);
QScriptValue fun = engine->newFunction(myPrintFunction);
fun.setData(engine->newQObject(output));
engine->globalObject().setProperty("print", fun);
connect(run, SIGNAL(clicked()), this, SLOT(runScript()));
}
void Console::runScript()
{
QString command = input->toPlainText();
QScriptValue result = engine->evaluate(command);
output->append(result.toString());
}
QScriptValue QtPrintFunction(QScriptContext *context, QScriptEngine *engine)
{
QString result;
for (int i = 0; i < context->argumentCount(); ++i) {
if (i > 0)
result.append(" ");
result.append(context->argument(i).toString());
}
QScriptValue calleeData = context->callee().data();
QTextEdit *edit = qobject_cast<QTextEdit*>(calleeData.toQObject());
edit->append(result);
return engine->undefinedValue();
}
QScriptValue myPrintFunction(QScriptContext *context, QScriptEngine *engine)
{
QString result;
for (int i = 0; i < context->argumentCount(); ++i) {
if (i > 0)
result.append(" ");
result.append(context->argument(i).toString());
}
return engine->toScriptValue(result);
}
Console::~Console()
{
}Run Code Online (Sandbox Code Playgroud)
输入1:
print(123);
Run Code Online (Sandbox Code Playgroud)
输出(Qt文件QtPrintFunction()):
123
undefined
Run Code Online (Sandbox Code Playgroud)
输出(我的版本myPrintFunction()):
123
Run Code Online (Sandbox Code Playgroud)
输入2:
for (i = 0; i < 3; i++)
print(i);
Run Code Online (Sandbox Code Playgroud)
输出(Qt文件QtPrintFunction()):
0
1
2
未定义
输出(myPrintFunction()):
2
输入3:
print("Stack");
print("Overflow");
Run Code Online (Sandbox Code Playgroud)
输出(Qt文件QtPrintFunction()):
堆
溢出
未定义
输出(我的版本myPrintFunction()):
溢出
虽然一开始myPrintFunction似乎工作得很好,但是当print脚本中有两个以上调用时,它不起作用,只执行最后一个脚本print.
并不是说 return 是必须的undefinedValue(),但是当你这样做时,就和不返回任何东西是一样的。或者本质上,就好像您将函数声明为void print(...),可以这么说。
这就是它所做的QtPrintFunction——它返回“无”。但它确实有一个副作用,即无论何时调用它,都会将其参数附加到内部数据对象。print这就是为什么您可以获得传递给对象的所有值output。
现在,当您调用时,它会返回最后engine->evaluate()计算的表达式的值。所以,你只能得到最后一个值。myPrintFunction
因此,如果您要输入以下内容:
print("Stack");
print("Overflow");
"garbage";
Run Code Online (Sandbox Code Playgroud)
你只会返回garbage(双关语),因为这是最后一个计算的表达式。
但是,如果您要输入以下内容:
print("Stack") + '\n' +
print("Overflow");
Run Code Online (Sandbox Code Playgroud)
正如您所期望的,您将获得这两个值。
此外,如果您输入:
result = "";
for (i = 0; i < 3; i++)
result += print(i) + '\n';
Run Code Online (Sandbox Code Playgroud)
您也会得到您所期望的。
希望这能解释为什么你的函数会这样运行。
但是,我认为这不是您想要实现的目标。所以...继续前进。
您可以做的一件事是定义myPrintFunction如下:
QScriptValue myPrintFunction(QScriptContext *context, QScriptEngine *engine)
{
static QString result;
for (int i = 0; i < context->argumentCount(); ++i) {
if (i > 0)
result.append(" ");
result.append(context->argument(i).toString());
}
result.append('\n');
return engine->toScriptValue(result);
}
Run Code Online (Sandbox Code Playgroud)
这将按照您期望的方式“工作”。唯一的问题是你无法清除 的值result。如果这对你有用,那就这样了。
有一种更好的方法可以做到这一点,这可能是定义一个类,例如:
class QTrace: public QObject
{
...
void clear();
void append(const QString& value);
const QString& get();
}
Run Code Online (Sandbox Code Playgroud)
并将该类的对象传递给fun.setData(engine->newQObject(trace))并将您的函数定义为:
QScriptValue myPrintFunction(QScriptContext *context, QScriptEngine *engine)
{
QString result;
for (int i = 0; i < context->argumentCount(); ++i) {
if (i > 0)
result.append(" ");
result.append(context->argument(i).toString());
}
result.append('\n');
QScriptValue calleeData = context->callee().data();
QTrace *trace = qobject_cast<QTrace*>(calleeData.toQObject());
trace->append(result);
return engine->undefinedValue();
}
Run Code Online (Sandbox Code Playgroud)
最后,您可以将runScript函数更改为:
trace->clear();
QScriptValue result = engine->evaluate(command);
if(result.isError())
output->append(result.toString());
else
output->append(trace->get());
Run Code Online (Sandbox Code Playgroud)
或者可能还有其他方法,但希望能帮助您朝着正确的方向前进。
| 归档时间: |
|
| 查看次数: |
612 次 |
| 最近记录: |