繁体   English   中英

在为QScriptEngine重新定义“print()”函数时返回“未定义值”有什么意义?

[英]What's the point of returning an “Undefined Value” when re-defining “print()” function for QScriptEngine?

[背景]

QScriptEngine的默认print()函数将结果打印到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();
 }

起初,我怀疑是否需要通过return engine->undefinedValue();返回“Undefined Value” return engine->undefinedValue(); ,看起来像参数*engine的作用就是返回这个空值。

所以这就是我改变功能的方法:

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
}

我认为对我来说更合理:从脚本引擎返回一个评估的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);

评估和输出:

QString command = input->toPlainText();
QScriptValue result = engine->evaluate(command);
output->append(result.toString());

[可编码]

(需要Qt版本> 4)

test.pro

 QT += core gui widgets script TARGET = Test TEMPLATE = app SOURCES += main.cpp\\ console.cpp HEADERS += console.h 

main.cpp中

 #include <QApplication> #include "console.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); Console w; w.show(); return app.exec(); } 

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_H 

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() { } 


[例]

输入1:

print(123);

输出(Qt文档QtPrintFunction() ):

123
undefined

输出(我的版本myPrintFunction() ):

123

输入2:

for (i = 0; i < 3; i++)
    print(i);

输出(Qt文档QtPrintFunction() ):

0

1

2

未定义

输出( myPrintFunction() ):

2


输入3:

print("Stack");
print("Overflow");

输出(Qt文档QtPrintFunction() ):

溢出

未定义

输出(我的版本myPrintFunction() ):

溢出


[题]

尽管myPrintFunction看起来工作得很好,但是当脚本中调用了两个以上的print时,它才会起作用,其中只会执行最后一次print

对于打印功能,似乎返回“未定义值”是必需的。 但为什么???

返回undefinedValue()并不是必须的,但是当你这样做时,它就像没有返回任何内容一样。 或者基本上,好像您将函数声明为void print(...) ,可以这么说。

这就是QtPrintFunction作用 - 它返回“无”。 但是无论何时调用它,它都会产生将其参数附加到内部数据对象的副作用。 这就是为什么你得到所有传递给值printoutput对象。

现在,当您调用engine->evaluate()它将返回上次计算的表达式的值。 因此,使用myPrintFunction您只能获得最后一个值。

所以,如果您要输入以下内容:

print("Stack");
print("Overflow");
"garbage";

你只会得到garbage回来(双关语),因为这是最后一次评估的表达式。

但是,如果你输入这个:

print("Stack") + '\n' +
print("Overflow");

你会得到两个值,如你所料。

此外,如果您输入:

result = "";
for (i = 0; i < 3; i++)
    result += print(i) + '\n';

你也会得到你所期望的。

希望这能解释为什么你的功能按照它们的方式运行。

但是,我不认为这是你想要实现的目标。 所以...向前移动。

可以做的一件事是定义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);
}

这将按照您期望的方式“工作”。 唯一的问题是你无法清除result的值。 如果这对你有用,那就是那个。

有一种更好的方法可以做到这一点,这可能是为了定义一个类,例如:

class QTrace: public QObject
{
    ...
    void clear();
    void append(const QString& value);
    const QString& get();
}

并将该类的对象传递给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();
}

最后,您可以将runScript函数更改为:

trace->clear();

QScriptValue result = engine->evaluate(command);
if(result.isError())
    output->append(result.toString());
else
    output->append(trace->get());

或者可能有其他方式,但希望能帮助你让球在正确的方向上滚动。

快速回答:您不需要返回undefinedValue。 你可以退回任何你想要的东西。 但是, engine->evaluate()只能返回一个值,我认为这是混乱的根源。

看看评估代码:

QString command = input->toPlainText();
QScriptValue result = engine->evaluate(command);
output->append(result.toString());

这将获取一个脚本字符串并对其进行评估,将结果值分配到result ,然后将其附加到QTextEdit控件。 evaluate()的返回值将是脚本的最后一个值。 例如:

QString command = "var a=1, b=2; a; b;";
QScriptValue result = engine->evaluate(command);
output->append(result.toString());

result将包含2,然后将记录到QTextEdit控件。

那么,发生了什么? 以此输入为例:

print("Stack");
print("Overflow");

使用QtPrintFunction ,作为QtPrintFunction实现的一部分,“Stack”和“Overflow”被添加到output控件中。 evaluate()完成时,最后一个语句是print("Overflow") ,它返回undefined。 然后,评估代码获取该返回值并将其添加到output ,从而导致:

Stack
Overflow
undefined

使用myPrintFunction ,该实现不会将任何内容记录到output ,而是返回值。 结果是evaluate()函数只返回最后一个值(“溢出”),从而产生以下输出:

Overflow

这是你所看到的。

由于您要将输出重定向到自己的自定义文本编辑器,因此需要更改此代码块:

QScriptEngine *engine = new QScriptEngine(this); 
 QTextEdit *input = new QTextEdit(this);
 //QTextEdit *output = new QTextEdit(this);
 YourCustomEditor *output = getYourCustomEditor();

 // Use my revised print function : 
 QScriptValue fun = engine->newFunction(myPrintFunction);
 fun.setData(engine->newQObject(output)); // pass your editor in
 engine->globalObject().setProperty("print", fun);

然后在myPrintFunction您需要以与YourCustomEditor类似的方式将输出发送到QtPrintFunction 然后您不再需要从evaluate()输出结果:

QString command = input->toPlainText();
QScriptValue result = engine->evaluate(command);
// output->append(result.toString()); <- not needed anymore

我以前曾多次使用嵌入式解释器,事情很快就会混乱。 希望这很明显可以提供帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM