在为 QScriptEngine 重新定义"print()"函数时返回"Undefined Value"有什么意义?
What's the point of returning an "Undefined Value" when re-defining "print()" function for QScriptEngine?
[背景]
默认print()
函数QScriptEngine
将结果打印到Qt Creator IDE的终端进行调试。因此,如果我们要自己制作 ECMA 脚本解释器,则必须将输出重定向到我们的文本编辑器。
文档">使应用程序可编写脚本"的这一部分自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();
返回"未定义的值",看起来参数*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
主.cpp
#include <QApplication>
#include "console.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Console w;
w.show();
return app.exec();
}
控制台.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
控制台.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
阿拉伯数字
定义
输出 ( myPrintFunction()
(:
阿拉伯数字
输入 3:
print("Stack");
print("Overflow");
输出(Qt文档QtPrintFunction()
(:
叠
溢出
定义
输出(我的版本 myPrintFunction()
(:
溢出
[问题]
尽管myPrintFunction
起初似乎工作正常,但当脚本中调用了两个以上的print
时,它不起作用,其中只会执行最后print
。
似乎返回"未定义的值"对于打印功能是必要的。但是为什么???
并不是说有必要返回undefinedValue()
,但是当你这样做时,这与不返回任何东西是一样的。或者本质上,好像你声明了函数 void print(...)
,可以这么说。
这就是QtPrintFunction
所做的 - 它返回"无"。但它确实有一个副作用,即在调用它时将其参数附加到内部数据对象。这就是在 output
对象中获取传递给print
的所有值的原因。
现在,当您调用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
实现的一部分添加到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
中,您需要以类似于QtPrintFunction
的方式将输出发送到YourCustomEditor
。然后你不再需要从evaluate()
输出结果:
QString command = input->toPlainText();
QScriptValue result = engine->evaluate(command);
// output->append(result.toString()); <- not needed anymore
我以前曾多次使用嵌入式口译员,事情很快就会变得混乱。希望这足够清楚,可以提供帮助。
- 瓦尔格林德:数学函数"Conditional jump or move depends on uninitialised value(s)"
- 我的项目不会像"undefined reference to `grpc::g_core_codegen_interface'"那样使用未定义的引用错误进行编译
- Visual Studio Code "undefined reference to `WinMain@16'"
- 使用 MATLAB 编码器生成C++代码:编译错误"undefined reference to `rgb2gray_tbb_real64'"
- "Undefined class"作为is_base_of的论据
- 为什么创建友元类的实例会导致"undefined reference to"错误?
- 为什么static_assert错误:即使我传递常量"expression must have a constant value"?
- Tensorflow c++ api undefined reference to 'tflite::D efaultErrorReporter()'
- 为什么我会" void value not ignored as it ought to be"?
- 方法错误"not all control paths return a value"和方法不返回值
- C++/SDL "initial value of reference to a non-const must be an lvalue"
- VSCode C/C++ Intellisense issue: Undefined identifiers (Linu
- 如何在 c++ 中理解这样的代码 [request->headers().Method()->value().getStringView())]
- std::<key-value>不同类型的对向量
- 与卡特琳娜一起卷曲C++失败并得到"Undefined symbols for architecture x86_64"
- c++ visual studio 64bit | save registers value
- 初始化数组、"memset"或" {//value} "的最佳方法是什么?
- 如何解决类成员函数中的"return a value"错误?
- 在为 QScriptEngine 重新定义"print()"函数时返回"Undefined Value"有什么意义?
- 使用 llvm::Function::d ump(),链接器可以"undefined reference to `llvm::Value::dump() const'"