[英]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
作用 - 它返回“無”。 但是無論何時調用它,它都會產生將其參數附加到內部數據對象的副作用。 這就是為什么你得到所有傳遞給值print
的output
對象。
現在,當您調用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.