[英]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.