Qt Script(一)

这篇博客介绍了Qt对ECMAScript的支持,以及如何在Qt应用程序中使用脚本类如QScriptEngine和QScriptValue进行脚本编程。Qt Script基于ECMAScript标准,提供了与C++对象交互的能力,包括注册自定义属性、使用信号和槽机制。还讲解了如何在脚本环境中使用QObject,并控制其所有权。
Qt provides support for application scripting with ECMAScript. The following guides and references cover aspects of programming with ECMAScript and Qt.
Qt用ECMAScript为应用程序提供了脚本支持。以下指南和参考设计了ECMAScript和Qt的各个方面
Scripting Classes
脚本类
The following classes add scripting capabilities to Qt applications.
下面的类为Qt应用程序增加了脚本功能
QScriptClass
Interface for defining custom behavior of (a class of) Qt Script objects
为Qt脚本对象定义自定义行为的接口
QScriptClassPropertyIterator
Iterator interface for custom Qt Script objects
自定义Qt脚本对象的迭代器接口
QScriptContext
Represents a Qt Script function invocation
代表一个Qt脚本函数调用
QScriptContextInfo
Additional information about a QScriptContext
关于一个QScriptContext的额外信息
QScriptEngine
Environment for evaluating Qt Script code
Qt脚本代码的执行环境
QScriptEngineAgent
Interface to report events pertaining to QScriptEngine execution
报告跟Qt引擎执行相关事件的接口
QScriptEngineDebugger
QScriptEngine debugger JS引擎调试器
QScriptProgram
Encapsulates a Qt Script program
封装了一个Qt脚本程序
QScriptString
Acts as a handle to "interned" strings in a QScriptEngine
充当内部字符串的句柄在脚本引擎中
QScriptSyntaxCheckResult
The result of a script syntax check
脚本语法检查的结果
QScriptValue
Acts as a container for the Qt Script data type
充当Qt脚本数据类型的容器
QScriptValueIterator
Java-style iterator for QScriptValue
QScriptValue的Java风格的迭代器
QScriptable
Access to the Qt Script environment from Qt C++ member functions
从Qt C++成员函数中访问Qt的脚本环境


Language Overview
语言概述
Qt Script is based on the ECMAScript scripting language, as defined in standard ECMA-262. Microsoft's JScript, and Netscape's JavaScript are also based on the ECMAScript standard. For an overview of ECMAScript, see the ECMAScript reference. If you are not familiar with the ECMAScript language, there are several existing tutorials and books that cover this subject, such as JavaScript: The Definitive Guide.
Qt脚本是基于ECMAScript脚本语言,按ECMA-262标准定义。微软的JScript和网景的JavaScript也是基于ECMAScript标准。可以看ECMAScript参考文档对ECMAScript有一个概览。如果你不熟悉ECMAScript语言,这也有一些教程和书涉及这个主题,例如JavaScript指南。
Basic Usage
基本用法
To evaluate script code, you create a QScriptEngine and call its evaluate() function, passing the script code (text) to evaluate as argument.
为了执行脚本代码,你可以创建一个JS引擎并且调用它的执行函数(evaluate)传递一个脚本代码文本作为evaluate的参数
QScriptEngine engine;
qDebug() << "the magic number is:" << engine.evaluate("1 + 2").toNumber();
The return value will be the result of the evaluation (represented as a QScriptValue object); this can be converted to standard C++ and Qt types.
返回值是代码执行的结果(是一个QScriptValue对象),可以被转换成标准C++/Qt类型
Custom properties can be made available to scripts by registering them with the script engine. This is most easily done by setting properties of the script engine's Global Object:
通过用脚本引擎注册的自定义属性可以在脚本里被访问。这很容易通过脚本引擎的Glabal Object来设置属性做到。
engine.globalObject().setProperty("foo", 123);
qDebug() << "foo times two is:" << engine.evaluate("foo * 2").toNumber();
This places the properties in the script environment, thus making them available to script code.
属性在脚本环境中因此他们可以被脚本代码访问。
Making a QObject Available to the Script Engine
使得一个QObject对象可以被脚本引擎使用
Any QObject-based instance can be made available for use with scripts.
任何基于QObject的实例都可以使用脚本来访问。
When a QObject is passed to the QScriptEngine::newQObject() function, a Qt Script wrapper object is created that can be used to make the QObject's signals, slots, properties, and child objects available to scripts.
当将一个QObject被传递给QScriptEngine::newQObject()函数,一个QtScript包装对象将被创建,可以被脚本访问QObject的信号,槽,属性和子对象。
Here's an example of making an instance of a QObject subclass available to script code under the name "myObject":
这有一个例子可以使得QObject子类的实例在脚本里用"myObject"名字来访问。
QScriptEngine engine;
QObject *someObject = new MyObject;
QScriptValue objectValue = engine.newQObject(someObject);
engine.globalObject().setProperty("myObject", objectValue);


This will create a global variable called myObject in the script environment. The variable serves as a proxy to the underlying C++ object. Note that the name of the script variable can be anything; i.e., it is not dependent upon QObject::objectName().
这将创建一个被称作myObject的全局变量在脚本环境中。这个变量充当C++对象的代理。注意脚本变量的名字可以是任何,它不依赖于QObject::objectName().
The newQObject() function accepts two additional optional arguments: one is the ownership mode, and the other is a collection of options that allow you to control certain aspects of how the QScriptValue that wraps the QObject should behave. We will come back to the usage of these arguments later.
newQobject()函数接受两个额外可选的参数:一个是所有权模式,另一个是一个可选项的集合,允许你控制一些特定的方面关于如何控制包裹QObject的QScriptValue行为。我们稍后将回来介绍这些参数的用法。
Using Signals and Slots
使用信号和槽
Qt Script adapts Qt's central Signals and Slots feature for scripting. There are three principal ways to use signals and slots with Qt Script:
Qt Script为脚本适配Qt的信号和槽特性。这有三种主要的方法来使用信号和槽用Qt Script
Hybrid C++/script: C++ application code connects a signal to a script function. The script function can, for example, be a function that the user has typed in, or one that you have read from a file. This approach is useful if you have a QObject but don't want to expose the object itself to the scripting environment; you just want a script to be able to define how a signal should be reacted to, and leave it up to the C++ side of your application to establish the connection.
混合C++/Script:C++应用代码连接一个信号到一个脚本函数,例如脚本函数可以是用户已经定义的或者你从一个文件中读取的。这种方法是有用的如果你有一个QObject但是不想把这个对象本身暴漏给脚本环境。你只是想定义一个脚本来相应信号。并且将建立连接留给你应用程序的C++一边。
Hybrid script/C++: A script can connect signals and slots to establish connections between pre-defined objects that the application exposes to the scripting environment. In this scenario, the slots themselves are still written in C++, but the definition of the connections is fully dynamic (script-defined).
混合script/C++:一个脚本可以连接信号和槽,预先定义在应用程序中暴露给脚本环境的对象。在这种情况下,槽本身仍可以在C++中写但是连接的定义是完全动态的(脚本定义)。
Purely script-defined: A script can both define signal handler functions (effectively "slots written in Qt Script"), and set up the connections that utilize those handlers. For example, a script can define a function that will handle the QLineEdit::returnPressed() signal, and then connect that signal to the script function.
纯脚本定义:一个脚本可以定义信号处理函数(实际上,槽也可以在Qt Script中写)并且利用这些处理程序建立连接。例如,一个脚本可以定义一个函数将处理QLineEdit::returnPressed()信号并且然后连接信号到脚本函数。
Use the qScriptConnect() function to connect a C++ signal to a script function. In the following example a script signal handler is defined that will handle the QLineEdit::textChanged() signal:
使用qScriptConnect()函数来连接一个C++信号到一个脚本函数。在下面的例子中一个脚本信号处理函数被定义,将处理QLineEdit::textChanged()信号。
QScriptEngine eng;
QLineEdit *edit = new QLineEdit(...);
QScriptValue handler = eng.evaluate("(function(text) { print('text was changed to', text); })");
qScriptConnect(edit, SIGNAL(textChanged(const QString &)), QScriptValue(), handler);


The first two arguments to qScriptConnect() are the same as you would pass to QObject::connect() to establish a normal C++ connection. The third argument is the script object that will act as the this object when the signal handler is invoked; in the above example we pass an invalid script value, so the this object will be the Global Object. The fourth argument is the script function ("slot") itself. The following example shows how the this argument can be put to use:
首先qScriptConnect()前两个参数跟QObject::connect是相同的,来建立一个正常的C++连接。第三个参数是脚本对象将是脚本对象来充当this对象当信号处理函数被调用。在上面的例子中我们传递一个无效的脚本值因此这个对象将是一个全局对象。第四个参数是脚本函数本身。下面的例子展示了这个参数如何使用:
QLineEdit *edit1 = new QLineEdit(...);
QLineEdit *edit2 = new QLineEdit(...);


QScriptValue handler = eng.evaluate("(function() { print('I am', this.name); })");
QScriptValue obj1 = eng.newObject();
obj1.setProperty("name", "the walrus");
QScriptValue obj2 = eng.newObject();
obj2.setProperty("name", "Sam");


qScriptConnect(edit1, SIGNAL(returnPressed()), obj1, handler);
qScriptConnect(edit2, SIGNAL(returnPressed()), obj2, handler);
We create two QLineEdit objects and define a single signal handler function. The connections use the same handler function, but the function will be invoked with a different this object depending on which object's signal was triggered, so the output of the print() statement will be different for each.
我们创建了两个QLineEdit对象并且定义了一个信号处理函数。多个连接使用了相同的处理函数但是函数将被调用,用不同的this对象依赖于那个对象的信号被触发,因此print语句将输出不同的结果。
In script code, Qt Script uses a different syntax for connecting to and disconnecting from signals than the familiar C++ syntax; i.e., QObject::connect(). To connect to a signal, you reference the relevant signal as a property of the sender object, and invoke its connect() function. There are three overloads of connect(), each with a corresponding disconnect() overload. The following subsections describe these three forms.
在脚本代码中,Qt Script使用了不同与熟悉的C++语法来连接到信号和从信号断开连接。为了连接一个信号,你可以引用关联的信号作为sender对象的一个属性,并且调用connect函数。这有三个重载的connect(),每一个都对应一个disconnect()重载。下面的分段描述这三种形式。
Signal to Function Connections
信号到函数连接
connect(function)


In this form of connection, the argument to connect() is the function to connect to the signal.
在这种连接形式中,connect的参数是连接到信号的函数
function myInterestingScriptFunction() {
    // ...
}
// ...
myQObject.somethingChanged.connect(myInterestingScriptFunction);
The argument can be a Qt Script function, as in the above example, or it can be a QObject slot, as in the following example:
这个参数可以是一个Qt Script函数,就像上面的例子或者可以是一个QObject的槽就像下面的例子
myQObject.somethingChanged.connect(myOtherQObject.doSomething);
When the argument is a QObject slot, the argument types of the signal and slot do not necessarily have to be compatible; Qt Script will, if necessary, perform conversion of the signal arguments to match the argument types of the slot.
当参数是一个QObject槽,信号和槽的参数不必须是兼容的,如果需要Qt Script将执行转换信号的参数匹配槽的参数类型
To disconnect from a signal, you invoke the signal's disconnect() function, passing the function to disconnect as argument:
为了从一个信号断开连接,你可以调用信号的disconnect函数通过将函数作为disconnect的参数
myQObject.somethingChanged.disconnect(myInterestingFunction);
myQObject.somethingChanged.disconnect(myOtherQObject.doSomething);
When a script function is invoked in response to a signal, the this object will be the Global Object.
当一个脚本函数被调用回应一个信号时,这个对象将是一个全局对象。
Signal to Member Function Connections
信号跟成员函数连接
connect(thisObject, function)


In this form of the connect() function, the first argument is the object that will be bound to the variable, this, when the function specified using the second argument is invoked.
在这种形式的connect函数中,第一个参数是被绑定到变量的对象,这时使用第二个参数指定的函数被调用。
If you have a push button in a form, you typically want to do something involving the form in response to the button's clicked signal; passing the form as the this object makes sense in such a case.
如果你有一个pushButton,你想要做一些事情来回应button的单击信号,在这种情况下,传递button作为this对象是有道理的
var obj = { x: 123 };
var fun = function() { print(this.x); };
myQObject.somethingChanged.connect(obj, fun);
To disconnect from the signal, pass the same arguments to disconnect():
为了断开从这个槽,传递相同的参数给disconnect()
myQObject.somethingChanged.disconnect(obj, fun);
Signal to Named Member Function Connections
信号跟命名成员函数连接
connect(thisObject, functionName)


In this form of the connect() function, the first argument is the object that will be bound to the variable, this, when a function is invoked in response to the signal. The second argument specifies the name of a function that is connected to the signal, and this refers to a member function of the object passed as the first argument (thisObject in the above scheme).
在这种形式的connect函数,第一个参数是被绑定到变量的对象,当回应信号的时候函数被调用。第二个参数指定了一个被连接到信号的函数名并且这涉及一个对象的成员函数
Note that the function is resolved when the connection is made, not when the signal is emitted.
注意当连接成功的时候函数被决定而不是当信号被发出时。
var obj = { x: 123, fun: function() { print(this.x); } };
myQObject.somethingChanged.connect(obj, "fun");
To disconnect from the signal, pass the same arguments to disconnect():
为了从信号断开连接,传递相同的参数给disconnect()
myQObject.somethingChanged.disconnect(obj, "fun");
Error Handling
错误处理
When connect() or disconnect() succeeds, the function will return undefined; otherwise, it will throw a script exception. You can obtain an error message from the resulting Error object. Example:
当connect()或者disconnect()成功后,函数将返回undefined;否则它将抛出一个脚本异常,你可以从一个错误对象中获取错误信息。例如
try {
    myQObject.somethingChanged.connect(myQObject, "slotThatDoesntExist");
} catch (e) {
    print(e);
}
Emitting Signals from Scripts
从脚本是发射信号
To emit a signal from script code, you simply invoke the signal function, passing the relevant arguments:
为了从脚本代码中发射一个信号,你可以简单地调用一个信号函数通过关联参数
myQObject.somethingChanged("hello");
It is currently not possible to define a new signal in a script; i.e., all signals must be defined by C++ classes.
一般是不可能在脚本中定义一个新的信号,所有的信号必须被定义在C++类中。
Overloaded Signals and Slots
重载的信号和槽
When a signal or slot is overloaded, Qt Script will attempt to pick the right overload based on the actual types of the QScriptValue arguments involved in the function invocation. For example, if your class has slots myOverloadedSlot(int) and myOverloadedSlot(QString), the following script code will behave reasonably:
当一个信号或者槽被重载,Qt Script将尝试基于涉及调用函数的QScriptValue参数真实的类型来选择正确的重载函数。     
myQObject.myOverloadedSlot(10);   // will call the int overload
myQObject.myOverloadedSlot("10"); // will call the QString overload
You can specify a particular overload by using array-style property access with the normalized signature of the C++ function as the property name:
你可以通过使用数组风格的属性来指定一个特殊的重载用规范化的C++函数签名作为属性名
myQObject['myOverloadedSlot(int)']("10");   // call int overload; the argument is converted to an int
myQObject['myOverloadedSlot(QString)'](10); // call QString overload; the argument is converted to a string
If the overloads have different number of arguments, Qt Script will pick the overload with the argument count that best matches the actual number of arguments passed to the slot.
如果重载有不同的参数数量,Qt Scrip将选择参数数量最匹配真实参数数量的槽。
For overloaded signals, Qt Script will throw an error if you try to connect to the signal by name; you have to refer to the signal with the full normalized signature of the particular overload you want to connect to.
对于重载的信号,Qt Script将抛出一个错误,如果你视图通过名字连接到信号,你必须指出信号,用完全规范的你想要连接的特殊重载的签名
Accessing Properties
访问属性
The properties of the QObject are available as properties of the corresponding Qt Script object. When you manipulate a property in script code, the C++ get/set method for that property will automatically be invoked. For example, if your C++ class has a property declared as follows:
QObject的属性可以被Qt Script对象用一致的属性访问。当你在脚本代码操作一个属性时,C++的属性的get/set方法将自动被调用。例如如果你的C++类有一个下面声明的属性:
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled)
then script code can do things like the following:
然后脚本代码就可以这样使用
myQObject.enabled = true;


// ...


myQObject.enabled = !myQObject.enabled;
Accessing Child QObjects
访问QObject的子类
Every named child of the QObject (that is, for which QObject::objectName() is not an empty string) is by default available as a property of the Qt Script wrapper object. For example, if you have a QDialog with a child widget whose objectName property is "okButton", you can access this object in script code through the expression
每一个被命名的QObject孩子都默认是作为一个Qt Script包装对象的属性。例如如果你有一个QDialog带有一个子窗口对象名属性是"okButton",你可以在脚本中访问这个对象用下面的表达式。
myDialog.okButton
Since objectName is itself a Q_PROPERTY, you can manipulate the name in script code to, for example, rename an object:
由于objectName本身也是一个Q+PROPERTY,你也可以在脚本代码中操作名字例如重命名这个对象。
myDialog.okButton.objectName = "cancelButton";
// from now on, myDialog.cancelButton references the button
You can also use the functions findChild() and findChildren() to find children. These two functions behave identically to QObject::findChild() and QObject::findChildren(), respectively.
你也可以使用findChild()和findChildren()来发现children。这两个函数行为是相同的和QObject::findChild()和QObject::findChildren.                                                        
For example, we can use these functions to find objects using strings and regular expressions:
例如,我们可以使用这些函数发现对象使用字符串和规则表达式
var okButton = myDialog.findChild("okButton");
if (okButton != null) {
   // do something with the OK button
}


var buttons = myDialog.findChildren(RegExp("button[0-9]+"));
for (var i = 0; i < buttons.length; ++i) {
   // do something with buttons[i]
}
You typically want to use findChild() when manipulating a form that uses nested layouts; that way the script is isolated from the details about which particular layout a widget is located in.
当你操作一个表格内嵌了布局器,你可以使用findChild().这种方法脚本从关于选择特殊布局里的widget的细节里分离。
Controlling QObject Ownership
控制QObject所有权
Qt Script uses garbage collection to reclaim memory used by script objects when they are no longer needed; an object's memory can be automatically reclaimed when it is no longer referenced anywhere in the scripting environment. Qt Script lets you control what happens to the underlying C++ QObject when the wrapper object is reclaimed (i.e., whether the QObject is deleted or not); you do this when you create an object by passing an ownership mode as the second argument to QScriptEngine::newQObject().
Qt Script使用了垃圾回收机制来回收被脚本对象的内存当它们不再被需要的时候。一个对象的内存可以被自动回收当它在脚本环境的任何地方都不在引用的时候。当封装对象被回收时Qt Script让你控制C++对象(QObject是否要被删除)。当你创建一个对象的时候传递一个ownership方式作为QScriptEngine::newQObject()的第二个参数。
Knowing how Qt Script deals with ownership is important, since it can help you avoid situations where a C++ object isn't deleted when it should be (causing memory leaks), or where a C++ object is deleted when it shouldn't be (typically causing a crash if C++ code later tries to access that object).
了解Qt Script如何处理所有权是重要的,因为它可以帮助你避免当C++对象应该被删除的时候而没有被删除(内存泄漏)或者它不应该被删除的时候而被删除(如果之后的C++代码访问这个对象会导致一个异常)                       
Qt Ownership
Qt所有权
By default, the script engine does not take ownership of the QObject that is passed to QScriptEngine::newQObject(); the object is managed according to Qt's object ownership (see Object Trees & Ownership). This mode is appropriate when, for example, you are wrapping C++ objects that are part of your application's core; that is, they should persist regardless of what happens in the scripting environment. Another way of stating this is that the C++ objects should outlive the script engine.
默认情况下,脚本引擎不会取得传递给QSriptEngine::newQObject()的QObject的所有权;这个对象将被管理根据Qt对象的所有权。这种模式是合适的,当你封装的C++对象是你的应用程序核心的一部分,就是说它们应该保持不管脚本环境中发生了什么.另一种表述就是C++对象应该比脚本引擎生存周期更长。
Script Ownership
脚本所有权
Specifying QScriptEngine::ScriptOwnership as the ownership mode will cause the script engine to take full ownership of the QObject and delete it when it determines that it is safe to do so (i.e., when there are no more references to it in script code). This ownership mode is appropriate if the QObject does not have a parent object, and/or the QObject is created in the context of the script engine and is not intended to outlive the script engine.
指定QScriptEngine::ScriptOwnership作为所有权模式将导致脚本引擎完全拥有QObject并且决定合适删除它是安全的。(当脚本代码中没有任何地方引用它)。这种所有权模式是合适的如果QObject没有一个父对象,并且/或者QObject是在脚本引擎的上下文中创建的并且不希望比脚本引擎生存周期更长。
For example, a constructor function that constructs QObjects only to be used in the script environment is a good candidate:
例如,一个构造函数是一个很好的候选只是构造用于脚本环境的QObject.
QScriptValue myQObjectConstructor(QScriptContext *context, QScriptEngine *engine)
{
  // let the engine manage the new object's lifetime.
  让引擎管理新建对象的生存周期。
  return engine->newQObject(new MyQObject(), QScriptEngine::ScriptOwnership);
}
Auto-Ownership
自动所有权
With QScriptEngine::AutoOwnership the ownership is based on whether the QObject has a parent or not. If the Qt Script garbage collector finds that the QObject is no longer referenced within the script environment, the QObject will be deleted only if it does not have a parent.
使用QScriptEngine::AutoOwnership的所有权基于QObject是否有一个父亲.如果Qt Script垃圾回收器发现了QObject在脚本环境中不再被引用,Qobject如果没有一个父对象将被删除。
What Happens When Someone Else Deletes the QObject?
当别人删除QObject会发生什么?
It is possible that a wrapped QObject is deleted outside of Qt Script's control; i.e., without regard to the ownership mode specified. In this case, the wrapper object will still be an object (unlike the C++ pointer it wraps, the script object won't become null). Any attempt to access properties of the script object will, however, result in a script exception being thrown.
一个封装的对象在脚本控制之外删除是可能的,不考虑指定的所有权模式。在这种情况下,封装的对象将仍然是一个对象(不想C++指针的封装,脚本对象不会编程null).任何试图访问脚本对象的属性将导致一个脚本异常被抛出。
Note that QScriptValue::isQObject() will still return true for a deleted QObject, since it tests the type of the script object, not whether the internal pointer is non-null. In other words, if QScriptValue::isQObject() returns true but QScriptValue::toQObject() returns a null pointer, this indicates that the QObject has been deleted outside of Qt Script (perhaps accidentally).
注意QScriptValue::isQobject()将仍会返回一个true为删除QObject.因为它测试了脚本对象的类型,内部指针是否是non-null.也就是说如果QScriptValue::isQobject()返回true但是QScriptValue::toQObject()返回空指针。这暗示QObject已经在Qt Script之外删除了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值