![]() |
Home · All Classes · Main Classes · Grouped Classes · Modules · Functions | ![]() |
[Previous: QtSvg Module] [Qt's Modules] [Next: QtXml Module]
The QtScript module provides classes for making Qt applications scriptable. More...
QScriptContext | The QScriptContext class represents a Qt Script function invocation. |
---|---|
QScriptEngine | The QScriptEngine class provides an environment for evaluating Qt Script code. |
QScriptExtensionPlugin | The QScriptExtensionPlugin class provides an abstract base for custom QScript extension plugins. |
QScriptValue | The QScriptValue class acts as a container for the Qt Script data types. |
QScriptValueIterator | The QScriptValueIterator class provides a Java-style iterator for QScriptValue. |
QScriptable | The QScriptable class provides access to the Qt Script environment from Qt C++ member functions. |
Applications that use Qt's Script classes need to be configured to be built against the QtScript module. To include the definitions of the module's classes, use the following directive:
#include <QtScript>
To link against the module, add this line to your qmake .pro file:
QT += script
The QtScript module is part of the Qt Desktop Edition and the Qt Open Source Edition.
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.
ECMA-262 gives the following overview of ECMAScript:
ECMAScript is object-based: basic language and host facilities are provided by objects, and an ECMAScript program is a cluster of communicating objects. An ECMAScript object is [a collection of properties] [...] Properties are containers that hold other objects, primitive values, or methods. A primitive value is a member of one of the following built-in types: Undefined, Null, Boolean, Number, and String; an object is a member of the remaining built-in type Object; and a method is a function associated with an object via a property.
ECMAScript defines a collection of built-in objects that round out the definition of ECMAScript entities. These built-in objects include the Global object, the Object object, the Function object, the Array object, the String object, the Boolean object, the Number object, the Math object, the Date object, the RegExp object and the Error objects Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError and URIError.
ECMAScript syntax intentionally resembles Java syntax. ECMAScript syntax is relaxed to enable it to serve as an easy-to-use scripting language. For example, a variable is not required to have its type declared nor are types associated with properties, and defined functions are not required to have their declarations appear textually before calls to them.
ECMA-262 gives the following description of ECMAScript objects:
ECMAScript does not contain proper classes such as those in C++, Smalltalk, or Java, but rather, supports constructors which create objects by executing code that allocates storage for the objects and initialises all or part of them by assigning initial values to their properties. [...] Each constructor has a Prototype property that is used to implement prototype-based inheritance and shared properties. Objects are created by using constructors in new expressions; for example, new String("A String") creates a new String object. Invoking a constructor without using new has consequences that depend on the constructor. For example, String("A String") produces a primitive string, not an object.
ECMAScript supports prototype-based inheritance. Every constructor has an associated prototype, and every object created by that constructor has an implicit reference to the prototype (called the object's prototype) associated with its constructor. Furthermore, a prototype may have a non-null implicit reference to its prototype, and so on; this is called the prototype chain. When a reference is made to a property in an object, that reference is to the property of that name in the first object in the prototype chain that contains a property of that name. In other words, first the object mentioned directly is examined for such a property; if that object contains the named property, that is the property to which the reference refers; if that object does not contain the named property, the prototype for that object is examined next; and so on.
Unlike class-based object languages, properties can be added to objects dynamically by assigning values to them. That is, constructors are not required to name or assign values to all or any of the constructed object's properties.
By passing a QObject to the scripting engine (using QScriptEngine::newQObject()), this object and all its signals, slots, properties, and child objects are made available to scripts. Because Qt Script uses Qt's meta object system, there is no need to implement any additional wrappers or bindings.
Here's an example of making a QObject available to script code under the name "myQObject":
QScriptEngine engine; QObject *someQObject = ...; QScriptValue qobjectValue = engine.newQObject(someQObject); engine.globalObject().setProperty("myQObject", qobjectValue);
To connect to a signal, you invoke the connect() function of the signal from script code, passing the function to invoke in response to the signal as argument:
function myInterestingScriptFunction() { ... } ... myQObject.somethingChanged.connect(myInterestingScriptFunction);
The argument can be a Qt Script function, as in the previous example, or it can be a QObject slot, as in the following example:
myQObject.somethingChanged.connect(myOtherQObject.doSomething);
To disconnect from a signal, you invoke the signal's disconnect() function, passing the function to disconnect as argument:
myQObject.somethingChanged.disconnect(myInterestingFunction); myQObject.somethingChanged.disconnect(myOtherQObject.doSomething);
To emit a signal from script code, you simply invoke the signal function, passing the relevant arguments:
myQObject.somethingChanged("hello");
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:
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled)
then script code can do things like the following:
myQObject.enabled = true; ... myQObject.enabled = !myQObject.enabled;
Every named child of the QObject is available as a property of the corresponding Qt Script object. For example, if you have a QDialog whose objectName() is "okButton", you can access this object in script code through the expression
myDialog.okButton
Since objectName is itself a Q_PROPERTY, you can manipulate the name in script code:
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. Example:
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.
This section explains how to implement application objects and provides the necessary technical background material.
Making C++ classes and objects available to a scripting language is not trivial since scripting languages are more dynamic than C++ and it must be possible to introspect objects (query information such as functions names, function signatures, properties, etc., at runtime). Standard C++ doesn't provide for this.
We can achieve the functionality we want by extending C++, using C++'s own facilities so our code is still standard C++. The Qt meta object system provides the necessary additional functionality. It allows us to write using an extended C++ syntax, but converts this into standard C++ using a small utility program called moc (Meta Object Compiler). Classes that wish to take advantage of the meta object facilities are either subclasses of QObject, or use the Q_OBJECT macro. Qt has used this approach for many years and it has proven to be solid and reliable. Qt Script uses this meta object technology to provide scripters with dynamic access to C++ classes and objects.
To completely understand how to make C++ objects available to Qt Script, some basic knowledge of the Qt meta object system is very helpful. We recommend that you read the Qt Object Model. The information in this document and the documents it links to are very useful for understanding how to implement application objects, however this knowledge is not essential. To make an object available in Qt Script, it must derive from QObject. All classes which derive from QObject are introspective and can provide the information needed by the scripting engine, e.g. classname, functions, signatures, etc., at runtime. Because we obtain the information we need about classes dynamically at run time, there is no need to write wrappers for QObject derived classes.
The meta object system makes information about slots dynamically available at runtime. This means that for QObject derived classes, only the slots are automatically made available to scripts. This is very convenient, because in practice we normally only want to make specially chosen functions available to scripters. When you create a QObject subclass, make sure that the functions you want to be available to scripters are public slots:
class MyObject : public QObject
{
Q_OBJECT
public:
MyObject( ... );
void aNonScriptableFunction();
public slots: // these functions (slots) will be available in Qt Script
void calculate( ... );
void setEnabled( bool enabled );
bool isEnabled() const;
private:
....
};
In the example above, aNonScriptableFunction() is not declared as a slot, so it will not be available in Qt Script. The other three functions will automatically be made available in Qt Script.
In the previous example, if we wanted to get or set a property using Qt Script we would have to write code like the following:
var obj = new MyObject; obj.setEnabled( true ); print( "obj is enabled: " + obj.isEnabled() );
Scripting languages often provide a property syntax to modify and retrieve properties (in our case the enabled state) of an object. Many script programmers would want to write the above code like this:
var obj = new MyObject; obj.enabled = true; print( "obj is enabled: " + obj.enabled );
To make this possible, you must define properties in the C++ QObject subclass. The class declaration of MyObject must look like the following to declare a property enabled of the type bool, which should use the function setEnabled(bool) as its setter function and the function isEnabled() as its getter function:
class MyObject : public QObject { Q_OBJECT // define the enabled property Q_PROPERTY( bool enabled WRITE setEnabled READ isEnabled ) public: MyObject( ... ); void aNonScriptableFunction(); public slots: // these functions (slots) will be available in Qt Script void calculate( ... ); void setEnabled( bool enabled ); bool isEnabled() const; private: .... };
The only difference from the original code is the use of the macro Q_PROPERTY, which takes the type and name of the property, and the names of the setter and getter functions as arguments.
In the Qt object model, signals are used as a notification mechanism between QObjects. This means one object can connect a signal to another object's slot and every time the signal is fired (emitted) the slot is called. This connection is established using the QObject::connect() function. This mechanism is also available to Qt Script programmers. The C++ code for declaring a signal is no different for a C++ class that is to be used by Qt Script than a C++ class used with Qt.
class MyObject : public QObject { Q_OBJECT // define the enabled property Q_PROPERTY( bool enabled WRITE setEnabled READ isEnabled ) public: MyObject( ... ); void aNonScriptableFunction(); public slots: // these functions (slots) will be available in Qt Script void calculate( ... ); void setEnabled( bool enabled ); bool isEnabled() const; signals: // the signals void enabledChanged( bool newState ); private: .... };
The only change this time is to declare a signals section, and declare the relevant signal in it. Now the script writer can write a function and connect to the object like this:
function enabledChangedHandler( b )
{
print( "state changed to: " + b );
}
function init()
{
var obj = new MyObject();
// connect a script function to the signal
obj["enabledChanged(bool)"].connect(enabledChangedHandler);
obj.enabled = true;
print( "obj is enabled: " + obj.enabled );
}
The previous section described how to implement C++ objects which can be used in Qt Script. Application objects are the same kind of objects, and they make your application's functionality available to Qt Script scripters. Since the C++ application is already written in Qt, many objects are already QObjects. The easiest approach would be to simply add all these QObjects as application objects to the scripting engine. For small applications this might be sufficient, but for larger applications this is probably not the right approach. The problem is that this method reveals too much of the internal API and gives script programmers access to application internals which should not be exposed. Generally, the best way of making application functionality available to scripters is to code some QObjects which define the applications public API using signals, slots, and properties. This gives you complete control of the functionality you make available. The implementation of these objects simply calls the functions in the application which do the real work. So instead of making all your QObjects available to the scripting engine, just add the wrapper QObjects.
[Previous: QtSvg Module] [Qt's Modules] [Next: QtXml Module]
Copyright © 2007 Trolltech | Trademarks | Qt 4.3.0beta |