javascript — какой смысл возвращать & quot; неопределенное значение & quot; при повторном определении & quot; print () & quot; функция для 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 = appSOURCES += main.cpp\
console.cpp

HEADERS  += console.h

7

Решение

Дело не в том, что НУЖНО возвращаться 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());

Или, возможно, есть другие способы, но, надеюсь, поможет вам заставить мяч катиться в правильном направлении.

2

Другие решения

Быстрый ответ: вам не нужно возвращать 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, «Стек» и «Переполнение» добавляются к output контроль как часть QtPrintFunction реализация. Когда evaluate() заканчивается, последнее утверждение было print("Overflow") который возвращает неопределенное. Затем код оценки принимает это возвращаемое значение и добавляет его к 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

Я много раз работал со встроенными интерпретаторами, и все может быстро запутаться. Надеюсь, это достаточно ясно, чтобы помочь.

1

По вопросам рекламы [email protected]