簡體   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