[英]What's the point of returning an “Undefined Value” when re-defining “print()” function for QScriptEngine?
The default print()
function of QScriptEngine
prints the result to the terminal of Qt Creator IDE for debugging purpose. QScriptEngine
的默认print()
函数将结果打印到Qt Creator IDE的终端以进行调试。 As a result, the output must be redirected to our texteditor if we are going to make a ECMA script interpreter ourselves. 因此,如果我们要自己制作ECMA脚本解释器,则必须将输出重定向到我们的texteditor。
This part of the document " Making Applications Scriptable " remains untouched since Qt 4.3. 自Qt 4.3以来,文档“ 使应用程序可编写脚本 ”的这一部分保持不变。
Section " Redefining print() " : “ 重新定义打印() ”部分 :
Qt Script provides a built-in print() function that can be useful for simple debugging purposes.
Qt Script提供了一个内置的print()函数,可用于简单的调试。 The built-in print() function writes to standard output.
内置的print()函数写入标准输出。 You can redefine the print() function (or add your own function, eg debug() or log()) that redirects the text to somewhere else.
您可以重新定义print()函数(或添加您自己的函数,例如debug()或log()),将文本重定向到其他位置。 The following code shows a custom print() that adds text to a QPlainTextEdit.
以下代码显示了一个自定义print(),它将文本添加到QPlainTextEdit。
So here is the suggested re-definition of print()
: 所以这是建议的
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();
}
At first, I doubted the need of returning an "Undefined Value" by return engine->undefinedValue();
起初,我怀疑是否需要通过
return engine->undefinedValue();
返回“Undefined Value” return engine->undefinedValue();
, and it looks like the role of the argument *engine
is just to return this void value. ,看起来像参数
*engine
的作用就是返回这个空值。
So here is what I've done to change the function: 所以这就是我改变功能的方法:
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
}
which I think is more reasonable to me: returning an evaluated QScriptValue
from script engine, and the value can later be translated to QString
for output. 我认为对我来说更合理:从脚本引擎返回一个评估的
QScriptValue
,稍后可以将该值转换为QString
以进行输出。 This bypass the need of dynamic type cast, which could become messy especially for customized QObjects. 这绕过了动态类型转换的需要,特别是对于自定义QObject,它可能变得混乱。
For both kinds of print function, here is the exposition to the script engine: 对于这两种打印功能,这里是脚本引擎的说明:
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);
Evaluation and output: 评估和输出:
QString command = input->toPlainText();
QScriptValue result = engine->evaluate(command);
output->append(result.toString());
(Qt version > 4 is needed) (需要Qt版本> 4)
test.pro test.pro
QT += core gui widgets script TARGET = Test TEMPLATE = app SOURCES += main.cpp\\ console.cpp HEADERS += console.h
main.cpp 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 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 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() { }
Input 1: 输入1:
print(123);
Output (Qt Document QtPrintFunction()
): 输出(Qt文档
QtPrintFunction()
):
123
undefined
Output (My version myPrintFunction()
): 输出(我的版本
myPrintFunction()
):
123
Input 2: 输入2:
for (i = 0; i < 3; i++)
print(i);
Output (Qt Document QtPrintFunction()
): 输出(Qt文档
QtPrintFunction()
):
0
0
1
1
2
2
undefined
未定义
Output ( myPrintFunction()
): 输出(
myPrintFunction()
):
2
2
Input 3: 输入3:
print("Stack");
print("Overflow");
Output (Qt Document QtPrintFunction()
): 输出(Qt文档
QtPrintFunction()
):
Stack
堆
Overflow
溢出
undefined
未定义
Output (My version myPrintFunction()
): 输出(我的版本
myPrintFunction()
):
Overflow
溢出
Although myPrintFunction
seems to work fine at first, it didn't work when there are more than two print
called in a script, where only the last print
will be executed. 尽管
myPrintFunction
看起来工作得很好,但是当脚本中调用了两个以上的print
时,它才会起作用,其中只会执行最后一次print
。
It's not that it is NECESSARY to return undefinedValue()
, but when you do, it's the same as not returning anything. 返回
undefinedValue()
并不是必须的,但是当你这样做时,它就像没有返回任何内容一样。 Or essentially, as if you declared the function as void print(...)
, so to speak. 或者基本上,好像您将函数声明为
void print(...)
,可以这么说。
That's what the QtPrintFunction
does -- it returns "nothing". 这就是
QtPrintFunction
作用 - 它返回“无”。 But it does have a side effect of appending its argument to the internal data object, whenever you call it. 但是无论何时调用它,它都会产生将其参数附加到内部数据对象的副作用。 That's why you get all of the values passed to
print
in the output
object. 这就是为什么你得到所有传递给值
print
的output
对象。
Now, when you call engine->evaluate()
it returns the value of the last evaluated expression. 现在,当您调用
engine->evaluate()
它将返回上次计算的表达式的值。 So, with myPrintFunction
you get the last value only. 因此,使用
myPrintFunction
您只能获得最后一个值。
So, if you were to enter the following: 所以,如果您要输入以下内容:
print("Stack");
print("Overflow");
"garbage";
you will only get garbage
back (pun intended), as this was the last evaluated expression. 你只会得到
garbage
回来(双关语),因为这是最后一次评估的表达式。
But, if you were to enter this: 但是,如果你输入这个:
print("Stack") + '\n' +
print("Overflow");
you will get both values, as you expected. 你会得到两个值,如你所料。
Additionally, if you enter: 此外,如果您输入:
result = "";
for (i = 0; i < 3; i++)
result += print(i) + '\n';
you will also get what you expected. 你也会得到你所期望的。
Hopefully this explains why you functions behave the way they are. 希望这能解释为什么你的功能按照它们的方式运行。
However, I don't think this is what you are trying to achieve. 但是,我不认为这是你想要实现的目标。 So... moving right along.
所以...向前移动。
One thing you can do is to define the myPrintFunction
as follows: 您可以做的一件事是定义
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);
}
This will "work" the way you expected it to work. 这将按照您期望的方式“工作”。 The only problem is that you can't clear the value of
result
. 唯一的问题是你无法清除
result
的值。 If that works for you, then that will be that. 如果这对你有用,那就是那个。
There is a more betterer way to do this, which is probably to define a class, eg: 有一种更好的方法可以做到这一点,这可能是为了定义一个类,例如:
class QTrace: public QObject
{
...
void clear();
void append(const QString& value);
const QString& get();
}
and pass an object of that class to fun.setData(engine->newQObject(trace))
and define your function as: 并将该类的对象传递给
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();
}
Lastly, you would change your runScript
function to something like: 最后,您可以将
runScript
函数更改为:
trace->clear();
QScriptValue result = engine->evaluate(command);
if(result.isError())
output->append(result.toString());
else
output->append(trace->get());
Or there are probably other ways, but hopefully will help you get the ball rolling in the right direction. 或者可能有其他方式,但希望能帮助你让球在正确的方向上滚动。
The quick answer: you don't need to return undefinedValue. 快速回答:您不需要返回undefinedValue。 You can return anything you want.
你可以退回任何你想要的东西。 However,
engine->evaluate()
can only return a single value, which I think is the source of the confusion. 但是,
engine->evaluate()
只能返回一个值,我认为这是混乱的根源。
Take a look at the evaluation code: 看看评估代码:
QString command = input->toPlainText();
QScriptValue result = engine->evaluate(command);
output->append(result.toString());
This takes a script string and evaluates it, assigning the resulting value into result
, where it is then appended to the QTextEdit
control. 这将获取一个脚本字符串并对其进行评估,将结果值分配到
result
,然后将其附加到QTextEdit
控件。 The return value of evaluate()
is going to be the last value of the script. evaluate()
的返回值将是脚本的最后一个值。 For example: 例如:
QString command = "var a=1, b=2; a; b;";
QScriptValue result = engine->evaluate(command);
output->append(result.toString());
result
would contain 2, which would then get logged to the QTextEdit
control. result
将包含2,然后将记录到QTextEdit
控件。
So, what's happening? 那么,发生了什么? Take this input for example:
以此输入为例:
print("Stack");
print("Overflow");
When using the QtPrintFunction
, "Stack" and "Overflow" are added to the output
control as part of the QtPrintFunction
implementation. 使用
QtPrintFunction
,作为QtPrintFunction
实现的一部分,“Stack”和“Overflow”被添加到output
控件中。 When the evaluate()
finishes, the last statement was print("Overflow")
which returns undefined. 当
evaluate()
完成时,最后一个语句是print("Overflow")
,它返回undefined。 The evaluation code then takes that return value and adds it to the output
, resulting in: 然后,评估代码获取该返回值并将其添加到
output
,从而导致:
Stack
Overflow
undefined
When using the myPrintFunction
, that implementation doesn't log anything to the output
, but returns the value. 使用
myPrintFunction
,该实现不会将任何内容记录到output
,而是返回值。 The result is that the evaluate()
function only returns the last value ("Overflow"), resulting in this output: 结果是
evaluate()
函数只返回最后一个值(“溢出”),从而产生以下输出:
Overflow
Which is what you are seeing. 这是你所看到的。
Since you want to redirect output to your own custom text editor, you need to change this block of code: 由于您要将输出重定向到自己的自定义文本编辑器,因此需要更改此代码块:
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);
Then in myPrintFunction
you need to send the output to YourCustomEditor
in a way that's similar to the QtPrintFunction
. 然后在
myPrintFunction
您需要以与YourCustomEditor
类似的方式将输出发送到QtPrintFunction
。 Then you no longer need to output the result from evaluate()
: 然后您不再需要从
evaluate()
输出结果:
QString command = input->toPlainText();
QScriptValue result = engine->evaluate(command);
// output->append(result.toString()); <- not needed anymore
I've worked with embedded interpreters many times before and things can get confusing quickly. 我以前曾多次使用嵌入式解释器,事情很快就会混乱。 Hopefully this is clear enough to help.
希望这很明显可以提供帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.