По умолчанию 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
Дело не в том, что НУЖНО возвращаться 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
, «Стек» и «Переполнение» добавляются к 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
Я много раз работал со встроенными интерпретаторами, и все может быстро запутаться. Надеюсь, это достаточно ясно, чтобы помочь.