接着上一章
重定义print()
QtScript提供了一个内建的print()函数可用作简单的调试打印,内建的print()写到标准输出,你能重定义print()(或者添加自己的函数,例如debug()或者log())用于重定向,下面的代码显示了一个自定义的print()重定向到QPlainTextEdit.
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();
}
下面的代码是关于自定义print()函数的自定义方式
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QScriptEngine eng;
QPlainTextEdit edit;
QScriptValue fun = eng.newFunction(myPrintFunction);
fun.setData(eng.newQObject(&edit));
eng.globalObject().setProperty("print", fun);
eng.evaluate("print('hello', 'world')");
edit.show();
return app.exec();
}
QPlainTextEdit是被存储到脚本函数的自定义属性内部,当函数被调用时QPlainTextEdit能被找到。
Qt脚本扩展
QtScriptEngine::importExtension()函数用来加载插件到脚本引擎当中,插件添加一些额外的功能到引擎当中,例如:插件可能会提供所有的Qt亚瑟绘画API到脚本当中,使Qt脚本可以使用这些绘制类,目前没有脚本插件与QT一起发布。
如果你想开发一些Qt脚本功能提供给其他的Qt开发人员,developing an extension(例如,需要子类化QScriptExtensionPlugin)值得一看。
国际化
自从Qt4.5开始,Qt脚本支持国际化,Qt脚本支持C++国际化功能可以参考(Internationalization with Qt).
对原文本使用qsTr()功能
无论你的脚本使用什么文本“quoted text”显示给用户,确保可以通过QCoreApplication::translate()函数处理。实现这一点所必需的是使用qrTr()脚本函数。
myButton.text = qsTr("Hello world!");
这种写法占用户可看见的字符串的99%。
qsTr用脚本的名称作为转换的上下文,如果文件名称在你的脚本工程当中是不是唯一的文件名称,你需要使用qsTranslate()函数并且传递一个合适的参数,例如:
myButton.text = qsTranslate("MyAwesomeScript", "Hello world!");
如果你需要在函数外翻译文本,这里有两个函数可以帮助你,QT_TR_NOOP() 和 QT_TRANSLATE_NOOP().它们仅仅标记了下面描述的lupdate实用程序提取文本。在运行时,这些函数简单地返回文本以进行未修改的翻译。
QT_TR_NOOP():的例子
FriendlyConversation.prototype.greeting = function(type)
{
if (FriendlyConversation['greeting_strings'] == undefined) {
FriendlyConversation['greeting_strings'] = [
QT_TR_NOOP("Hello"),
QT_TR_NOOP("Goodbye")
];
}
return qsTr(FriendlyConversation.greeting_strings[type]);
}
QT_TRANSLATE_NOOP():的例子
FriendlyConversation.prototype.greeting = function(type)
{
if (FriendlyConversation['greeting_strings'] == undefined) {
FriendlyConversation['greeting_strings'] = [
QT_TRANSLATE_NOOP("FriendlyConversation", "Hello"),
QT_TRANSLATE_NOOP("FriendlyConversation", "Goodbye")
];
}
return qsTranslate("FriendlyConversation", FriendlyConversation.greeting_strings[type]);
}
动态文本用String.prototype.arg()
String.prototype.arg()函数提供了简单的替换方法
FileCopier.prototype.showProgress = function(done, total, currentFileName)
{
this.label.text = qsTr("%1 of %2 files copied.\nCopying: %3")
.arg(done)
.arg(total)
.arg(currentFileName);
}
制作翻译
一旦在整个脚本中使用了qsTr()和/或qsTranslate(),就可以开始生成程序中用户可见文本的翻译。
Qt语言手册提供了关于Qt的翻译工具、Qt语言工具、lupdate和lrelease的进一步信息。
QT脚本翻译需要执行下面三个过程:
1、运行lupdate获取从脚本源码文件中转换的文本,转换的结果将存储在一个ts文件中,综合运用
qsTr(), qsTranslate()和 QT_TR*_NOOP()函数生成ts文件(通常每种语言一个ts文件)。
2、准备ts类型的转换文件,用Qt Linguist对ts文件翻译,因为ts文件是xml格式的,你也可以手动编辑。
3、运行lrelease从TS文件中获取轻量级消息文件(QM文件),qm文件仅适合于最终使用。将TS文件视为“源文件”,并将QM文件视为“目标文件”。翻译器编辑TS文件,但是应用程序的用户只需要QM文件。这两种文件都是独立的平台和区域。
典型的应用,你需要在你的每个应用程序中重复这些步骤,lupdate实用程序尽其所能重用以前版本的翻译。
运行lupdate,你必须指定本地的脚本文件,提供一个生成的ts的文件名,例如:
lupdate myscript.qs -ts myscript_la.ts
从myscript.qs中提取转换文件,生成要转换的myscript_la.ts文件。
lupdate -extensions qs scripts/ -ts scripts_la.ts
从scripts文件加下提取所有的以.qs结尾的文件,生成一个转换文件scripts_la.ts。
或者,你能创建一个分离的qmake工程文件,并设置合适的SOURCES和TRANSLATIONS变量,将工程文件作为lupdate的输入。
lrelease myscript_la.ts
当运行lrelease时你必须指定ts文件的名字,或者,如果你用qmake工程文件管理脚本转换,你制定工程文件名,lrelease将生成myscript_la.qm文件,这是一个二进制的转换文件。
使用语言转换文件
在你的应用程序当中,你需要使用Qt::Translator::load()加载合适的用户语言文件,并用QCoreApplication::installTranslator()安装他们,最后,你必须调用QScriptEngine::installTranslatorFunctions(),这样才能使用脚本语言转换函数(qsTr(), qsTranslate()和QT_TR*_NOOP()),在脚本中使用qsTr(),必须将合适的文件名称传递到QScriptEngine::evaluate()的第二个参数。
linguist, lupdate 和 lrelease是被安装在Qt下的bin子目录中,点击Qt Linguist下的Help|Manual可以查看用户手册,手册中讲述了怎样开始。
Qt脚本中实现了所有的ECMA-262标准的对象和属性,查看ECMAScript reference相关的标准概述
1、__proto__
在脚本代码中 一个object的prototype(QScriptValue::prototype())可以通过__proto__ 属性访问,这个属性中含有 QScriptValue::Undeletable标记,例如:
var o = new Object();
(o.__proto__ === Object.prototype); // this evaluates to true
2、Object.prototype.__defineGetter__
在object的prototype中添加一个getter函数,第一个参数是属性名称,第二个参数是获取属性值的函数,当调用这个函数时,this将是被访问的属性的对象,例如:
var o = new Object();
o.__defineGetter__("x", function() { return 123; });
var y = o.x; // 123
3、Object.prototype.__defineSetter__
在object的prototype中添加一个setter函数,第一个参数是属性名称,第二个参数是设置属性值的函数,当调用这个函数时,this将是被访问的属性的对象,例如:
var o = new Object();
o.__defineSetter__("x", function(v) { print("and the value is:", v); });
o.x = 123; // will print "and the value is: 123"
4、Function.prototype.connect
这个函数会链接一个信号到一个槽,在Using Signals and Slots章节中描述了这个函数的用法 。
5、Function.prototype.disconnect
这个函数会结束一个信号的链接,在Using Signals and Slots章节中描述了这个函数的用法 。
6、QObject.prototype.findChild
这个函数的用法与QObject::findChild()相同。
7、QObject.prototype.findChildren
这个函数的用法与QObject::findChildren()相同。
8、QObject.prototype.toString
这个函数返回QObject的默认字符串
9、gc
这个函数调用垃圾回收
10、Error.prototype.backtrace
这个函数返回手动读取backtrace的结果,是一个字符串数组。
11、Error objects中还有额外的属性:lineNumber:错误发生的行数,fileName错误发生的文件名(如果
QScriptEngine::evaluate()中传入了文件名)。