Home · All Namespaces · All Classes · Main Classes · Grouped Classes · Modules · Functions

[Previous: QtOpenGL Module] [Qt's Modules] [Next: QtSql Module]

QtScript Module

The QtScript module provides classes for making Qt applications scriptable. More...

Classes

QScriptClassInterface for defining custom behavior of (a class of) Qt Script objects
QScriptClassPropertyIteratorIterator interface for custom Qt Script objects
QScriptContextRepresents a Qt Script function invocation
QScriptContextInfoAdditional information about a QScriptContext
QScriptEngineEnvironment for evaluating Qt Script code
QScriptEngineAgentInterface to report events pertaining to QScriptEngine execution
QScriptExtensionPluginAbstract base for custom QScript extension plugins
QScriptStringActs as a handle to "interned" strings in a QScriptEngine
QScriptValueActs as a container for the Qt Script data types
QScriptValueIteratorJava-style iterator for QScriptValue
QScriptableAccess to the Qt Script environment from Qt C++ member functions

Detailed Description

Configuring the Build Process

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 Full Framework Edition and the Qt Open Source Edition.

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.

Existing users of Qt Script for Applications (QSA) may find the Moving from QSA to Qt Script document useful when porting QSA scripts to Qt Script.

Basic Usage

To evaluate script code, you create a QScriptEngine and call its evaluate() function, passing the script code (text) to evaluate as argument.

     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.

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:

     QScriptValue val(&engine, 123);
     engine.globalObject().setProperty("foo", val);
     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

Any QObject-based instance can be made available for use with scripts.

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.

Here's an example of making an instance of a QObject subclass available to script code under the name "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().

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.

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:

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:

 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:

 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", QScriptValue(&eng, "the walrus"));
 QScriptValue obj2 = eng.newObject();
 obj2.setProperty("name", QScriptValue(&eng, "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.

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.

Signal to Function Connections

connect(function)

In this form of connection, the argument to connect() is the function to connect to the signal.

 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:

 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; QtScript will, if necessary, perform conversion of the signal arguments to match the argument types of the slot.

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);

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.

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.

 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():

 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).

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():

 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:

 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.

Overloaded Signals and Slots

When a signal or slot is overloaded, QtScript 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:

 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:

 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, QtScript will pick the overload with the argument count that best matches the actual number of arguments passed to the slot.

For overloaded signals, QtScript will connect to the most general overload, unless you refer to the signal with its full normalized signature.

Accessing Properties

The properties of the QObject are available as properties of the corresponding QtScript 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;

Accessing Child QObjects

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 QtScript 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

 myDialog.okButton

Since objectName is itself a Q_PROPERTY, you can manipulate the name in script code to, for example, rename an object:

 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.

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.

Controlling QObject Ownership

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().

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 Ownership

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 and Object 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.

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.

For example, a constructor function that constructs QObjects only to be used in the script environment is a good candidate:

 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 QtScript 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.

What Happens When Someone Else Deletes the 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.

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).

Customizing Access to the QObject

QScriptEngine::newQObject() can take a third argument which allows you to control various aspects of the access to the QObject through the QtScript wrapper object it returns.

QScriptEngine::ExcludeChildObjects specifies that child objects of the QObject should not appear as properties of the wrapper object.

QScriptEngine::ExcludeSuperClassProperties and QScriptEngine::ExcludeSuperClassMethods can be used to avoid exposing members that are inherited from the QObject's superclass. This is useful for defining a "pure" interface where inherited members don't make sense from a scripting perspective; e.g., you don't want script authors to be able to change the objectName property of the object or invoke the deleteLater() slot.

QScriptEngine::AutoCreateDynamicProperties specifies that properties that don't already exist in the QObject should be created as dynamic properties of the QObject, rather than as properties of the QtScript wrapper object. If you want new properties to truly become persistent properties of the QObject, rather than properties that are destroyed along with the wrapper object (and that aren't shared if the QObject is wrapped multiple times with QScriptEngine::newQObject()), you should use this option.

QScriptEngine::SkipMethodsInEnumeration specifies that signals and slots should be skipped when enumerating the properties of the QObject wrapper in a for-in script statement. This is useful when defining prototype objects, since by convention function properties of prototypes should not be enumerable.

Making a QObject-based Class New-able from a Script

The QScriptEngine::newQObject() function is used to wrap an existing QObject instance, so that it can be made available to scripts. A different scenario is that you want scripts to be able to construct new objects, not just access existing ones.

The Qt meta-type system currently does not provide dynamic binding of constructors for QObject-based classes. If you want to make such a class new-able from scripts, Qt Script can generate a reasonable script constructor for you; see QScriptEngine::scriptValueFromQMetaObject().

You can also use QScriptEngine::newFunction() to wrap your own factory function, and add it to the script environment; see QScriptEngine::newQMetaObject() for an example.

Enum Values

Values for enums declared with Q_ENUMS are not available as properties of individual wrapper objects; rather, they are properties of the QMetaObject wrapper object that can be created with QScriptEngine::newQMetaObject().

Conversion Between QtScript and C++ Types

QtScript will perform type conversion when a value needs to be converted from the script side to the C++ side or vice versa; for instance, when a C++ signal triggers a script function, when you access a QObject property in script code, or when you call QScriptEngine::toScriptValue() or QScriptEngine::fromScriptValue() in C++. QtScript provides default conversion operations for many of the built-in Qt types. You can change the conversion operation for a type (including your custom C++ types) by registering your own conversion functions with qScriptRegisterMetaType().

Default Conversion from Qt Script to C++

The following table describes the default conversion from a QScriptValue to a C++ type.

C++ TypeDefault Conversion
boolQScriptValue::toBoolean()
intQScriptValue::toInt32()
uintQScriptValue::toUInt32()
floatfloat(QScriptValue::toNumber())
doubleQScriptValue::toNumber()
shortshort(QScriptValue::toInt32())
ushortQScriptValue::toUInt16()
charchar(QScriptValue::toInt32())
ucharunsigned char(QScriptValue::toInt32())
qlonglongqlonglong(QScriptValue::toInteger())
qulonglongqulonglong(QScriptValue::toInteger())
QStringQScriptValue::toString()
QDateTimeQScriptValue::toDateTime()
QDateQScriptValue::toDateTime().date()
QRegExpQScriptValue::toRegExp()
QObject*QScriptValue::toQObject()
QWidget*QScriptValue::toQObject()
QVariantQScriptValue::toVariant()
QCharIf the QScriptValue is a string, the result is the first character of the string, or a null QChar if the string is empty; otherwise, the result is a QChar constructed from the unicode obtained by converting the QScriptValue to a ushort.
QStringListIf the QScriptValue is an array, the result is a QStringList constructed from the result of QScriptValue::toString() for each array element; otherwise, the result is an empty QStringList.
QVariantListIf the QScriptValue is an array, the result is a QVariantList constructed from the result of QScriptValue::toVariant() for each array element; otherwise, the result is an empty QVariantList.
QVariantMapIf the QScriptValue is an object, the result is a QVariantMap with a (key, value) pair of the form (propertyName, propertyValue.toVariant()) for each property, using QScriptValueIterator to iterate over the object's properties.
QObjectListIf the QScriptValue is an array, the result is a QObjectList constructed from the result of QScriptValue::toQObject() for each array element; otherwise, the result is an empty QObjectList.
QList<int>If the QScriptValue is an array, the result is a QList<int> constructed from the result of QScriptValue::toInt32() for each array element; otherwise, the result is an empty QList<int>.

Additionally, QtScript will handle the following cases:

Default Conversion from C++ to Qt Script

The following table describes the default behavior when a QScriptValue is constructed from a C++ type:

C++ TypeDefault Construction
voidQScriptEngine::undefinedValue()
boolQScriptValue(engine, value)
intQScriptValue(engine, value)
uintQScriptValue(engine, value)
floatQScriptValue(engine, value)
doubleQScriptValue(engine, value)
shortQScriptValue(engine, value)
ushortQScriptValue(engine, value)
charQScriptValue(engine, value)
ucharQScriptValue(engine, value)
QStringQScriptValue(engine, value)
qlonglongQScriptValue(engine, qsreal(value)). Note that the conversion may lead to loss of precision, since not all 64-bit integers can be represented using the qsreal type.
qulonglongQScriptValue(engine, qsreal(value)). Note that the conversion may lead to loss of precision, since not all 64-bit unsigned integers can be represented using the qsreal type.
QCharQScriptValue(this, value.unicode())
QDateTimeQScriptEngine::newDate(value)
QDateQScriptEngine::newDate(value)
QRegExpQScriptEngine::newRegExp(value)
QObject*QScriptEngine::newQObject(value)
QWidget*QScriptEngine::newQObject(value)
QVariantQScriptEngine::newVariant(value)
QStringListA new script array (created with QScriptEngine::newArray()), whose elements are created using the QScriptValue(QScriptEngine *, QString) constructor for each element of the list.
QVariantListA new script array (created with QScriptEngine::newArray()), whose elements are created using QScriptEngine::newVariant() for each element of the list.
QVariantMapA new script object (created with QScriptEngine::newObject()), whose properties are initialized according to the (key, value) pairs of the map.
QObjectListA new script array (created with QScriptEngine::newArray()), whose elements are created using QScriptEngine::newQObject() for each element of the list.
QList<int>A new script array (created with QScriptEngine::newArray()), whose elements are created using the QScriptValue(QScriptEngine *, int) constructor for each element of the list.

Other types (including custom types) will be wrapped using QScriptEngine::newVariant(). For null pointers of any type, the result is QScriptEngine::nullValue().

How to Design and Implement Application Objects

This section explains how to implement application objects and provides the necessary technical background material.

Making a C++ object available to Scripts Written in QtScript

Making C++ classes and objects available to a scripting language is not trivial because scripting languages tend to be more dynamic than C++, and it must be possible to introspect objects (query information such as function names, function signatures, properties, etc., at run-time). Standard C++ does not provide features 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. QtScript 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 in the simplest cases. To make an object available in QtScript, it must derive from QObject. All classes which derive from QObject can be introspected and can provide the information needed by the scripting engine at run-time; e.g., class name, functions, signatures. Because we obtain the information we need about classes dynamically at run-time, there is no need to write wrappers for QObject derived classes.

Making C++ Class Member Functions Available in QtScript

The meta-object system also makes information about signals and slots dynamically available at run-time. By default, for QObject subclasses, only the signals and 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 expose to QtScript are public slots.

For example, the following class definition enables scripting only for certain functions:

 class MyObject : public QObject
 {
     Q_OBJECT
 public:
     MyObject( ... );
     void aNonScriptableFunction();
 public slots: // these functions (slots) will be available in QtScript
     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 QtScript. The other three functions will automatically be made available in QtScript because they are declared in the public slots section of the class definition.

It is possible to make any function script-invokable by specifying the Q_INVOKABLE modifier when declaring the function:

 class MyObject : public QObject
 {
     Q_OBJECT
     public:
     Q_INVOKABLE void thisMethodIsInvokableInQtScript();
     void thisMethodIsNotInvokableInQtScript();
     ...
 };

Once declared with Q_INVOKABLE, the method can be invoked from QtScript code just as if it were a slot. Although such a method is not a slot, you can still specify it as the target function in a call to connect() in script code; connect() accepts both native and non-native functions as targets.

Making C++ Class Properties Available in QtScript

In the previous example, if we wanted to get or set a property using QtScript 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. For example, the following MyObject class declaration declares a boolean property called enabled, which uses the function setEnabled(bool) as its setter function and 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 QtScript
     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.

If you don't want a property of your class to be accessible in QtScript, you set the SCRIPTABLE attribute to false when declaring the property; by default, the SCRIPTABLE attribute is true. For example:

 Q_PROPERTY(int nonScriptableProperty READ foo WRITE bar SCRIPTABLE false)

Reacting to C++ Objects Signals in Scripts

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 emitted, the slot is called. This connection is established using the QObject::connect() function.

The signals and slots mechanism is also available to QtScript programmers. The code to declare a signal in C++ is the same, regardless of whether the signal will be connected to a slot in C++ or in QtScript.

 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 QtScript
     void calculate( ... );
     void setEnabled( bool enabled );
     bool isEnabled() const;
 signals: // the signals
     void enabledChanged( bool newState );
 private:
    ....
 };

The only change we have made to the code in the previous section is to declare a signals section with the relevant signal. Now, the script writer can define 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 );
 }

Design of Application Objects

The previous section described how to implement C++ objects which can be used in QtScript. Application objects are the same kind of objects, and they make your application's functionality available to QtScript 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 made available by the application. The implementations of these objects simply call 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.

Returning QObject Pointers

If you have a slot that returns a QObject pointer, you should note that, by default, Qt Script only handles conversion of the types QObject* and QWidget*. This means that if your slot is declared with a signature like "MyObject* getMyObject()", QtScript doesn't automatically know that MyObject* should be handled in the same way as QObject* and QWidget*. The simplest way to solve this is to only use QObject* and QWidget* in the method signatures of your scripting interface.

Alternatively, you can register conversion functions for your custom type with the qScriptRegisterMetaType() function. In this way, you can preserve the precise typing in your C++ declarations, while still allowing pointers to your custom objects to flow seamlessly between C++ and scripts. Example:

 class MyObject : public QObject
 {
     Q_OBJECT
     ...
 };
 Q_DECLARE_METATYPE(MyObject*)
 QScriptValue myObjectToScriptValue(QScriptEngine *engine, MyObject* const &in)
 { return engine->newQObject(in); }
 void myObjectFromScriptValue(const QScriptValue &object, MyObject* &out)
 { out = qobject_cast<MyObject*>(object.toQObject()); }
 ...
 qScriptRegisterMetaType(&engine, myObjectToScriptValue, myObjectFromScriptValue);

Function Objects and Native Functions

In Qt Script, functions are first-class values; they are objects that can have properties of their own, just like any other type of object. They can be stored in variables and passed as arguments to other functions. Knowing how function calls in Qt Script behave is useful when you want to define and use your own script functions. This section discusses this matter, and also explains how you can implement native functions; that is, Qt Script functions written in C++, as opposed to functions written in the scripting language itself. Even if you will be relying mostly on the dynamic QObject binding that Qt Script provides, knowing about these powerful concepts and techniques is important to understand what's actually going on when script functions are executed.

The this Object

When a Qt Script function is invoked, the way in which it is invoked determines the this object when the function body is executed, as the following script example illustrates:

 var getProperty = function(name) { return this[name]; };
 name = "Global Object"; // creates a global variable
 print(getProperty("name")); // "Global Object"
 var myObject = { name: 'My Object' };
 print(getProperty.call(myObject, "name")); // "My Object"
 myObject.getProperty = getProperty;
 print(myObject.getProperty("name")); // "My Object"
 getProperty.name = "The getProperty() function";
 getProperty.getProperty = getProperty;
 getProperty.getProperty("name"); // "The getProperty() function"

An import thing to note is that in Qt Script, unlike C++ and Java, the this object is not part of the execution scope. This means that member functions (i.e., functions that operate on this) must always use the this keyword to access the object's properties. For example, the following script probably doesn't do what you want:

 var o = { a: 1, b: 2, sum: function() { return a + b; } };
 print(o.sum()); // reference error, or sum of global variables a and b!!

You will get a reference error saying that 'a is not defined' or, worse, two totally unrelated global variables a and b will be used to perform the computation, if they exist. Instead, the script should look like this:

 var o = { a: 1, b: 2, sum: function() { return this.a + this.b; } };
 print(o.sum()); // 3

Accidentally omitting the this keyword is a typical source of error for programmers who are used to the scoping rules of C++ and Java.

Wrapping a Native Function

Qt Script provides QScriptEngine::newFunction() as a way of wrapping a C++ function pointer; this enables you to implement a function in C++ and add it to the script environment, so that scripts can invoke your function as if it were a "normal" script function. Here is how the previous getProperty() function can be written in C++:

 QScriptValue getProperty(QScriptContext *ctx, QScriptEngine *eng)
 {
     QString name = ctx->argument(0).toString();
     return ctx->thisObject().property(name);
 }

Call QScriptEngine::newFunction() to wrap the function. This will produce a special type of function object that carries a pointer to the C++ function internally. Once the resulting wrapper has been added to the scripting environment (e.g., by setting it as a property of the Global Object), scripts can call the function without having to know nor care that it is, in fact, a native function.