1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
|
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
\group script
\title Scripting Classes and Overviews
\brief Classes that add scripting capabilities to Qt applications.
*/
/*!
\page scripting.html
\title Making Applications Scriptable
\ingroup frameworks-technologies
Qt 4.3 and later provides support for application scripting with ECMAScript.
The following guides and references cover aspects of programming with
ECMAScript and Qt.
\tableofcontents
\section1 Scripting Classes
The following classes add scripting capabilities to Qt applications.
\annotatedlist script
\section1 Language Overview
Qt Script is based on the ECMAScript scripting language, as defined
in standard \l{ECMA-262}. Microsoft's JScript, and Netscape's
JavaScript are also based on the ECMAScript standard. For an
overview of ECMAScript, see the
\l{ECMAScript Reference}{ECMAScript reference}.
If you are not familiar with the ECMAScript language, there are
several existing tutorials and books that cover this subject, such
as \l{JavaScript: The Definitive Guide}.
Existing users of \l{Qt Script for Applications (QSA)} may find the
\l{Moving from QSA to Qt Script} document useful when porting
QSA scripts to Qt Script.
\section1 Basic Usage
To evaluate script code, you create a QScriptEngine and call its
evaluate() function, passing the script code (text) to evaluate
as argument.
\snippet doc/src/snippets/qtscript/evaluation/main.cpp 0
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 \e{Global Object}:
\snippet doc/src/snippets/qtscript/registeringvalues/main.cpp 0
This places the properties in the script environment, thus making them
available to script code.
\section1 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 \c{"myObject"}:
\snippet doc/src/snippets/qtscript/registeringobjects/main.cpp 0
This will create a global variable called \c{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 \l{QScriptEngine::}{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.
\section2 Using Signals and Slots
Qt Script adapts Qt's central \l{Signals and Slots} feature for
scripting. There are three principal ways to use signals and slots
with Qt Script:
\list
\i \bold{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.
\i \bold{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).
\i \bold{Purely script-defined}: A script can both define signal
handler functions (effectively "slots written in Qt Script"),
\e{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.
\endlist
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:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 47
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 \c this object when the signal handler is invoked; in the above
example we pass an invalid script value, so the \c this object will
be the Global Object. The fourth argument is the script function
("slot") itself. The following example shows how the \c this argument
can be put to use:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 48
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 \c 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 \c{connect()} function. There
are three overloads of \c{connect()}, each with a corresponding
\c{disconnect()} overload. The following subsections describe these
three forms.
\section3 Signal to Function Connections
\c{connect(function)}
In this form of connection, the argument to \c{connect()} is the
function to connect to the signal.
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 2
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:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 3
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
\c{disconnect()} function, passing the function to disconnect
as argument:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 4
When a script function is invoked in response to a signal, the
\c this object will be the Global Object.
\section3 Signal to Member Function Connections
\c{connect(thisObject, function)}
In this form of the \c{connect()} function, the first argument
is the object that will be bound to the variable, \c 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
\c{clicked} signal; passing the form as the \c this object
makes sense in such a case.
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 5
To disconnect from the signal, pass the same arguments to \c{disconnect()}:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 6
\section3 Signal to Named Member Function Connections
\c{connect(thisObject, functionName)}
In this form of the \c{connect()} function, the first argument is
the object that will be bound to the variable, \c 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 (\c thisObject in the above scheme).
Note that the function is resolved when the connection is made, not
when the signal is emitted.
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 7
To disconnect from the signal, pass the same arguments to \c{disconnect()}:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 8
\section3 Error Handling
When \c{connect()} or \c{disconnect()} succeeds, the function will
return \c{undefined}; otherwise, it will throw a script exception.
You can obtain an error message from the resulting \c{Error} object.
Example:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 9
\section3 Emitting Signals from Scripts
To emit a signal from script code, you simply invoke the signal
function, passing the relevant arguments:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 10
It is currently not possible to define a new signal in a script;
i.e., all signals must be defined by C++ classes.
\section3 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
\c{myOverloadedSlot(int)} and \c{myOverloadedSlot(QString)}, the following
script code will behave reasonably:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 11
You can specify a particular overload by using array-style property access
with the \l{QMetaObject::normalizedSignature()}{normalized signature} of
the C++ function as the property name:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 12
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, 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.
\section2 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:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 13
then script code can do things like the following:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 14
\section2 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 \c{objectName} property is
\c{"okButton"}, you can access this object in script code through
the expression
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 15
Since \c{objectName} is itself a Q_PROPERTY, you can manipulate
the name in script code to, for example, rename an object:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 16
You can also use the functions \c{findChild()} and \c{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:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 17
You typically want to use \c{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.
\section2 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 \e{is}
deleted when it shouldn't be (typically causing a crash if C++ code
later tries to access that object).
\section3 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
\l{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.
\section3 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:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 18
\section3 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 \e{only} if it does not have a parent.
\section3 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).
\section2 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 \c{objectName} property of
the object or invoke the \c{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.
\section2 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.
\section2 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().
\section1 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().
\section2 Default Conversion from Qt Script to C++
The following table describes the default conversion from a
QScriptValue to a C++ type.
\table 80%
\header \o C++ Type \o Default Conversion
\row \o bool \o QScriptValue::toBool()
\row \o int \o QScriptValue::toInt32()
\row \o uint \o QScriptValue::toUInt32()
\row \o float \o float(QScriptValue::toNumber())
\row \o double \o QScriptValue::toNumber()
\row \o short \o short(QScriptValue::toInt32())
\row \o ushort \o QScriptValue::toUInt16()
\row \o char \o char(QScriptValue::toInt32())
\row \o uchar \o unsigned char(QScriptValue::toInt32())
\row \o qlonglong \o qlonglong(QScriptValue::toInteger())
\row \o qulonglong \o qulonglong(QScriptValue::toInteger())
\row \o QString \o An empty string if the QScriptValue is null
or undefined; QScriptValue::toString() otherwise.
\row \o QDateTime \o QScriptValue::toDateTime()
\row \o QDate \o QScriptValue::toDateTime().date()
\row \o QRegExp \o QScriptValue::toRegExp()
\row \o QObject* \o QScriptValue::toQObject()
\row \o QWidget* \o QScriptValue::toQObject()
\row \o QVariant \o QScriptValue::toVariant()
\row \o QChar \o If 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 \c{ushort}.
\row \o QStringList \o If 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.
\row \o QVariantList \o If 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.
\row \o QVariantMap \o If 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.
\row \o QObjectList \o If 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.
\row \o QList<int> \o 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>.
\endtable
Additionally, QtScript will handle the following cases:
\list
\i If the QScriptValue is a QObject and the target type name ends with
\c * (i.e., it is a pointer), the QObject pointer will be cast to the
target type with qobject_cast().
\i If the QScriptValue is a QVariant and the target type name ends with
\c * (i.e., it is a pointer), and the \l{QVariant::userType()}{userType()}
of the QVariant is the type that the target type points to, the result
is a pointer to the QVariant's data.
\i If the QScriptValue is a QVariant and it can be converted to the
target type (according to QVariant::canConvert()), the QVariant will
be cast to the target type with qvariant_cast().
\endlist
\section2 Default Conversion from C++ to Qt Script
The following table describes the default behavior when a QScriptValue is
constructed from a C++ type:
\table 80%
\header \o C++ Type \o Default Construction
\row \o void \o QScriptEngine::undefinedValue()
\row \o bool \o QScriptValue(engine, value)
\row \o int \o QScriptValue(engine, value)
\row \o uint \o QScriptValue(engine, value)
\row \o float \o QScriptValue(engine, value)
\row \o double \o QScriptValue(engine, value)
\row \o short \o QScriptValue(engine, value)
\row \o ushort \o QScriptValue(engine, value)
\row \o char \o QScriptValue(engine, value)
\row \o uchar \o QScriptValue(engine, value)
\row \o QString \o QScriptValue(engine, value)
\row \o qlonglong \o QScriptValue(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.
\row \o qulonglong \o QScriptValue(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.
\row \o QChar \o QScriptValue(this, value.unicode())
\row \o QDateTime \o \l{QScriptEngine::newDate()}{QScriptEngine::newDate}(value)
\row \o QDate \o \l{QScriptEngine::newDate()}{QScriptEngine::newDate}(value)
\row \o QRegExp \o \l{QScriptEngine::newRegExp()}{QScriptEngine::newRegExp}(value)
\row \o QObject* \o \l{QScriptEngine::newQObject()}{QScriptEngine::newQObject}(value)
\row \o QWidget* \o \l{QScriptEngine::newQObject()}{QScriptEngine::newQObject}(value)
\row \o QVariant \o \l{QScriptEngine::newVariant()}{QScriptEngine::newVariant}(value)
\row \o QStringList \o A new script array (created with
QScriptEngine::newArray()), whose elements are created using
the QScriptValue(QScriptEngine *, QString) constructor for
each element of the list.
\row \o QVariantList \o A new script array (created with
QScriptEngine::newArray()), whose elements are created using
QScriptEngine::newVariant() for each element of the list.
\row \o QVariantMap \o A new script object (created with
QScriptEngine::newObject()), whose properties are initialized
according to the (key, value) pairs of the map.
\row \o QObjectList \o A new script array (created with
QScriptEngine::newArray()), whose elements are created using
QScriptEngine::newQObject() for each element of the list.
\row \o QList<int> \o A new script array (created with
QScriptEngine::newArray()), whose elements are created using
the QScriptValue(QScriptEngine *, int) constructor for each
element of the list.
\endtable
Other types (including custom types) will be wrapped using
QScriptEngine::newVariant(). For null pointers of any type, the
result is QScriptEngine::nullValue().
\section1 How to Design and Implement Application Objects
This section explains how to implement application objects and
provides the necessary technical background material.
\section2 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 \l{moc}
(Meta-Object Compiler). Classes that wish to take advantage of the
meta-object facilities are either subclasses of QObject, or use the
\c{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 about the Qt \l{Object Model}
and \l{The Meta-Object System}, which are 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.
\section2 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:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 19
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 \c{public slots} section of the class
definition.
It is possible to make any function script-invokable by specifying
the \c{Q_INVOKABLE} modifier when declaring the function:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 20
Once declared with \c{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 \c{connect()} in script code; \c{connect()} accepts both
native and non-native functions as targets.
\section2 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:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 21
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:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 22
To make this possible, you must define properties in the C++ QObject
subclass. For example, the following \c MyObject class declaration
declares a boolean property called \c enabled, which uses the function
\c{setEnabled(bool)} as its setter function and \c{isEnabled()} as its
getter function:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 23
The only difference from the original code is the use of the macro
\c{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 \c{SCRIPTABLE} attribute to \c false when
declaring the property; by default, the \c{SCRIPTABLE} attribute is
\c true. For example:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 24
\section2 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.
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 25
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:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 26
\section2 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.
\section3 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:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 43
\section1 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.
\section2 Calling a Qt Script Function from C++
Calling a Qt Script function from C++ is achieved with the
QScriptValue::call() function. A typical scenario is that you evaluate a
script that defines a function, and at some point you want to call that
function from C++, perhaps passing it some arguments, and then handle the
result. The following script defines a Qt Script object that has a
toKelvin() function:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 90
The toKelvin() function takes a temperature in Kelvin as argument, and
returns the temperature converted to Celsius. The following snippet shows
how the toKelvin() function might be obtained and called from C++:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 91
If a script defines a global function, you can access the function as a
property of QScriptEngine::globalObject(). For example, the following script
defines a global function add():
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 56
C++ code might call the add() function as follows:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 92
As already mentioned, functions are just values in Qt Script; a function by
itself is not "tied to" a particular object. This is why you have to specify
a \c{this} object (the first argument to QScriptValue::call()) that the
function should be applied to.
If the function is supposed to act as a method (i.e. it can only be applied
to a certain class of objects), it is up to the function itself to check
that it is being called with a compatible \c{this} object.
Passing an invalid QScriptValue as the \c{this} argument to
QScriptValue::call() indicates that the Global Object should be used as the
\c{this} object; in other words, that the function should be invoked as a
global function.
\section2 The \c this Object
When a Qt Script function is invoked from a script, the \e{way} in which it
is invoked determines the \c this object when the function body is executed,
as the following script example illustrates:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 49
An important thing to note is that in Qt Script, unlike C++ and Java, the
\c this object is not part of the execution scope. This means that
member functions (i.e., functions that operate on \c this) must always
use the \c this keyword to access the object's properties. For example,
the following script probably doesn't do what you want:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 50
You will get a reference error saying that 'a is not defined' or, worse,
two totally unrelated global variables \c a and \c b will be used to
perform the computation, if they exist. Instead, the script should look
like this:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 51
Accidentally omitting the \c this keyword is a typical source of
error for programmers who are used to the scoping rules of C++ and Java.
\section2 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 \c{getProperty()} function can be written in C++:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 52
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.
Note that the name of the C++ function doesn't matter in the
scripting sense; the name by which the function is invoked by
scripts depends only on what you call the script object property
in which you store the function wrapper.
It is currently not possible to wrap member functions; i.e., methods
of a C++ class that require a \c this object.
\section2 The QScriptContext Object
A QScriptContext holds all the state associated with a particular
invocation of your function. Through the QScriptContext, you can:
\list
\i Get the arguments that were passed to the function.
\i Get the \c this object.
\i Find out whether the function was called with the \c new operator
(the significance of this will be explained later).
\i Throw a script error.
\i Get the function object that's being invoked.
\i Get the activation object (the object used to hold local variables).
\endlist
The following sections explain how to make use of this
functionality.
\section2 Processing Function Arguments
Two things are worth noting about function arguments:
\list 1
\o Any script function \mdash including native functions \mdash can
be invoked with any number of arguments. This means that it is up to
the function itself to check the argument count if necessary, and act
accordingly (e.g., throw an error if the number of arguments is
too large, or prepare a default value if the number is too small).
\o A value of any type can be supplied as an argument to any
function. This means that it is up to you to check the type of the
arguments if necessary, and act accordingly (e.g., throw an error
if an argument is not an object of a certain type).
\endlist
In summary: Qt Script does not automatically enforce any constraints on the
number or type of arguments involved in a function call.
\section3 Formal Parameters and the Arguments Object
A native Qt Script function is analogous to a script function that defines no
formal parameters and only uses the built-in \c arguments variable to
process its arguments. To see this, let's first consider how a
script would normally define an \c{add()} function that takes two
arguments, adds them together and returns the result:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 56
When a script function is defined with formal parameters, their
names can be viewed as mere aliases of properties of the \c
arguments object; for example, in the \c{add(a, b)} definition's
function body, \c a and \c arguments[0] refer to the same
variable. This means that the \c{add()} function can equivalently be
written like this:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 57
This latter form closely matches what a native implementation
typically looks like:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 58
\section3 Checking the Number of Arguments
Again, remember that the presence (or lack) of formal parameter
names in a function definition does not affect how the function
may be invoked; \c{add(1, 2, 3)} is allowed by the engine, as is
\c{add(42)}. In the case of the \c {add()} function, the function
really needs two arguments in order to do something useful. This
can be expressed by the script definition as follows:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 59
This would result in an error being thrown if a script invokes
\c{add()} with anything other than two arguments. The native
function can be modified to perform the same check:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 62
\section3 Checking the Types of Arguments
In addition to expecting a certain number of arguments, a function might
expect that those arguments are of certain types (e.g., that the first
argument is a number and that the second is a string). Such a function
should explicitly check the type of arguments and/or perform a conversion,
or throw an error if the type of an argument is incompatible.
As it is, the native implementation of \c{add()} shown above doesn't
have the exact same semantics as the script counterpart; this is
because the behavior of the Qt Script \c{+} operator depends on the
types of its operands (for example, if one of the operands is a string,
string concatenation is performed). To give the script function
stricter semantics (namely, that it should only add numeric
operands), the argument types can be tested:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 60
Then an invocation like \c{add("foo", new Array())} will
cause an error to be thrown.
The C++ version can call QScriptValue::isNumber() to perform similar
tests:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 63
A less strict script implementation might settle for performing an
explicit to-number conversion before applying the \c{+} operator:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 61
In a native implementation, this is equivalent to calling
QScriptValue::toNumber() without performing any type test first,
since QScriptValue::toNumber() will automatically perform a type
conversion if necessary.
To check if an argument is of a certain object type (class),
scripts can use the \c instanceof operator (e.g., \c{"arguments[0]
instanceof Array"} evaluates to true if the first argument is an
Array object); native functions can call QScriptValue::instanceOf().
To check if an argument is of a custom C++ type, you typically use
qscriptvalue_cast() and check if the result is valid. For object types,
this means casting to a pointer and checking if it is non-zero; for
value types, the class should have an \c{isNull()}, \c{isValid()}
or similar method. Alternatively, since most custom types are
transported in \l{QVariant}s, you can check if the script value is a
QVariant using QScriptValue::isVariant(), and then check if the
QVariant can be converted to your type using QVariant::canConvert().
\section3 Functions with Variable Numbers of Arguments
Because of the presence of the built-in \c arguments object,
implementing functions that take a variable number of arguments
is simple. In fact, as we have seen, in the technical sense \e{all}
Qt Script functions can be seen as variable-argument functions.
As an example, consider a concat() function that takes an arbitrary
number of arguments, converts the arguments to their string
representation and concatenates the results; for example,
\c{concat("Qt", " ", "Script ", 101)} would return "Qt Script 101".
A script definition of \c{concat()} might look like this:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 64
Here is an equivalent native implementation:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 65
A second use case for a variable number of arguments is to implement
optional arguments. Here's how a script definition typically does
it:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 66
And here's the native equivalent:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 67
A third use case for a variable number of arguments is to simulate
C++ overloads. This involves checking the number of arguments and/or
their type at the beginning of the function body (as already shown),
and acting accordingly. It might be worth thinking twice before
doing this, and instead favor unique function names; e.g., having
separate \c{processNumber(number)} and \c{processString(string)}
functions rather than a generic \c{process(anything)} function.
On the caller side, this makes it harder for scripts to accidentally
call the wrong overload (since they don't know or don't comprehend
your custom sophisticated overloading resolution rules), and on the
callee side, you avoid the need for potentially complex (read:
error-prone) checks to resolve ambiguity.
\section3 Accessing the Arguments Object
Most native functions use the QScriptContext::argument() function to
access function arguments. However, it is also possible to access
the built-in \c arguments object itself (the one referred to by the
\c arguments variable in script code), by calling the
QScriptContext::argumentsObject() function. This has three principal
applications:
\list
\o The \c arguments object can be used to easily forward a function
call to another function. In script code, this is what it
typically looks like:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 68
For example, \c{foo(10, 20, 30)} would result in the \c{foo()} function
executing the equivalent of \c{bar(10, 20, 30)}. This is useful if
you want to perform some special pre- or post-processing when
calling a function (e.g., to log the call to \c{bar()} without having
to modify the \c{bar()} function itself, like the above example), or if
you want to call a "base implementation" from a prototype
function that has the exact same "signature". In C++, the forwarding
function might look like this:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 69
\o The arguments object can serve as input to a QScriptValueIterator,
providing a generic way to iterate over the arguments. A debugger
might use this to display the arguments object in a general purpose
"Qt Script Object Explorer", for example.
\o The arguments object can be serialized (e.g., with JSON) and transferred
to another entity (e.g., a script engine running in another thread),
where the object can be deserialized and passed as argument to
another script function.
\endlist
\section2 Constructor Functions
Some script functions are constructors; they are expected to initialize
new objects. The following snippet is a small example:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 75
There is nothing special about constructor functions. In fact, any
script function can act as a constructor function (i.e., any function
can serve as the operand to \c{new}). Some functions behave differently
depending on whether they are called as part of a \c{new} expression
or not; for example, the expression \c{new Number(1)} will create a
Number object, whereas \c{Number("123")} will perform a type
conversion. Other functions, like \c{Array()}, will always create
and initialize a new object (e.g., \c{new Array()} and \c{Array()} have
the same effect).
A native Qt Script function can call the
QScriptContext::isCalledAsConstructor() function to determine if it
is being called as a constructor or as a regular function. When a
function is called as a constructor (i.e., it is the operand in a
\c{new} expression), this has two important implications:
\list
\i The \c this object, QScriptContext::thisObject(), contains
the new object to be initialized; the engine creates this
new object automatically before invoking your function. This means
that your native constructor function normally doesn't have to (and
shouldn't) create a new object when it is called as a
constructor, since the engine has already prepared a new
object. Instead your function should operate on the supplied
\c this object.
\i The constructor function should return an undefined value,
QScriptEngine::undefinedValue(), to tell the engine that the
\c this object should be the final result of the \c new
operator. Alternatively, the function can return the \c this
object itself.
\endlist
When QScriptContext::isCalledAsConstructor() returns false, how your
constructor handles this case depends on what behavior you desire.
If, like the built-in \c{Number()} function, a plain function call should
perform a type conversion of its argument, then you perform the conversion
and return the result. If, on the other hand, you want your constructor
to behave \e{as if it was called as a constructor} (with
\c{new}), you have to explicitly create a new object (that is,
ignore the \c this object), initialize that object, and return it.
The following example implements a constructor function that always
creates and initializes a new object:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 76
Given this constructor, scripts would be able to use either the
expression \c{new Person("Bob")} or \c{Person("Bob")} to create a
new \c{Person} object; both behave in the same way.
There is no equivalent way for a function defined in script
code to determine whether or not it was invoked as a constructor.
Note that, even though it is not considered good practice, there is
nothing that stops you from choosing to ignore the default
constructed (\c this) object when your function is called as a
constructor and creating your own object anyway; simply have the
constructor return that object. The object will "override" the
default object that the engine constructed (i.e., the default
object will simply be discarded internally).
\section2 Associating Data with a Function
Even if a function is global \mdash i.e., not associated with any particular
(type of) object \mdash you might still want to associate some data with it,
so that it becomes self-contained; for example, the function could have
a pointer to some C++ resource that it needs to access. If your application
only uses a single script engine, or the same C++ resource can/should be
shared among all script engines, you can simply use a static C++ variable
and access it from within the native Qt Script function.
In the case where a static C++ variable or singleton class is
not appropriate, you can call QScriptValue::setProperty() on the
function object, but be aware that those properties will also be
accessible to script code. The alternative is to use QScriptValue::setData();
this data is not script-accessible. The implementation can access this
internal data through the QScriptContext::callee() function, which
returns the function object being invoked. The following example
shows how this might be used:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 55
\section2 Native Functions as Arguments to Functions
As previously mentioned, a function object can be passed as argument
to another function; this is also true for native functions,
naturally. As an example, here's a native comparison function
that compares its two arguments numerically:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 53
The above function can be passed as argument to the standard
\c{Array.prototype.sort} function to sort an array numerically,
as the following C++ code illustrates:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 54
Note that, in this case, we are truly treating the native function
object as a value \mdash i.e., we don't store it as a property of the
scripting environment \mdash we simply pass it on as an "anonymous"
argument to another script function and then forget about it.
\section2 The Activation Object
Every Qt Script function invocation has an \e{activation object}
associated with it; this object is accessible through the
QScriptContext::activationObject() function. The activation object
is a script object whose properties are the local variables
associated with the invocation (including the arguments for which
the script function has a corresponding formal parameter name).
Thus, getting, modifying, creating and deleting local variables
from C++ is done using the regular QScriptValue::property() and
QScriptValue::setProperty() functions. The activation object itself
is not directly accessible from script code (but it is implicitly
accessed whenever a local variable is read from or written to).
For C++ code, there are two principal applications of the
activation object:
\list
\i The activation object provides a standard way to traverse the
variables associated with a function call, by using it as the input
to QScriptValueIterator. This is useful for debugging purposes.
\i The activation object can be used to prepare local variables
that should be available when a script is evaluated inline; this
can be viewed as a way of passing arguments to the script
itself. This technique is typically used in conjunction with
QScriptEngine::pushContext(), as in the following example:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 77
We create a temporary execution context, create a local variable
for it, evaluate the script, and finally restore the old context.
\endlist
\section2 Property Getters and Setters
A script object property can be defined in terms of a getter/setter
function, similar to how a Qt C++ property has read and write
functions associated with it. This makes it possible for a script to
use expressions like \c{object.x} instead of \c{object.getX()}; the
getter/setter function for \c{x} will implicitly be invoked
whenever the property is accessed. To scripts, the property looks
and behaves just like a regular object property.
A single Qt Script function can act as both getter and setter for
a property. When it is called as a getter, the argument count is 0.
When it is called as a setter, the argument count is 1; the argument
is the new value of the property. In the following example, we
define a native combined getter/setter that transforms the value
slightly:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 78
The example uses the internal data of the object to store and
retrieve the transformed value. Alternatively, the property
could be stored in another, "hidden" property of the object itself
(e.g., \c{__x__}). A native function is free to implement whatever
storage scheme it wants, as long as the external behavior of the
property itself is consistent (e.g., that scripts should not be able
to distinguish it from a regular property).
The following C++ code shows how an object property can be defined
in terms of the native getter/setter:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 79
When the property is accessed, like in the following script, the
getter/setter does its job behind the scenes:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 80
\note It is important that the setter function, not just the getter,
returns the value of the property; i.e., the setter should \e{not}
return QScriptValue::UndefinedValue. This is because the result of
the property assignment is the value returned by the setter, and
not the right-hand side expression. Also note that you normally
should not attempt to read the same property that the getter modifies
within the getter itself, since this will cause the getter to be
called recursively.
You can remove a property getter/setter by calling
QScriptValue::setProperty(), passing an invalid QScriptValue
as the getter/setter. Remember to specify the
QScriptValue::PropertyGetter/QScriptValue::PropertySetter flag(s),
otherwise the only thing that will happen is that the setter will be
invoked with an invalid QScriptValue as its argument!
Property getters and setters can be defined and installed by script
code as well, as in the following example:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 81
Getters and setters can only be used to implement "a priori
properties"; i.e., the technique can't be used to react to an access
to a property that the object doesn't already have. To gain total
control of property access in this way, you need to subclass
QScriptClass.
\section1 Making Use of Prototype-Based Inheritance
In ECMAScript, inheritance is based on the concept of \e{shared
prototype objects}; this is quite different from the class-based
inheritance familiar to C++ programmers. With QtScript, you can
associate a custom prototype object with a C++ type using
QScriptEngine::setDefaultPrototype(); this is the key to providing
a script interface to that type. Since the QtScript module is built
on top of Qt's meta-type system, this can be done for any C++ type.
You might be wondering when exactly you would need to use this
functionality in your application; isn't the automatic binding
provided by QScriptEngine::newQObject() enough? No, not under all
circumstances.
Firstly, not every C++ type is derived from QObject; types that
are not QObjects cannot be introspected through Qt's meta-object
system (they do not have properties, signals and slots). Secondly,
even if a type is QObject-derived, the functionality you want to
expose to scripts might not all be available, since it is unusual to
define every function to be a slot (and it's not always
possible/desirable to change the C++ API to make it so).
It is perfectly possible to solve this problem by using "conventional"
C++ techniques. For instance, the QRect class could effectively be
made scriptable by creating a QObject-based C++ wrapper class with
\c{x}, \c{y}, \c{width} properties and so on, which forwarded property
access and function calls to the wrapped value. However, as we shall
see, by taking advantage of the ECMAScript object model and combining
it with Qt's meta-object system, we can arrive at a solution that is
more elegant, consistent and lightweight, supported by a small API.
This section explains the underlying concepts of prototype-based
inheritance. Once these concepts are understood, the associated
practices can be applied throughout the QtScript API in order to
create well-behaved, consistent bindings to C++ that will fit nicely
into the ECMAScript universe.
When experimenting with QtScript objects and inheritance, it can be
helpful to use the interactive interpreter included with the
\l{Qt Script Examples}, located in \c{examples/script/qscript}.
\section2 Prototype Objects and Shared Properties
The purpose of a QtScript \e{prototype object} is to define
behavior that should be shared by a set of other QtScript
objects. We say that objects which share the same prototype object
belong to the same \e{class} (again, on the technical side this
should not to be confused with the class constructs of languages
like C++ and Java; ECMAScript has no such construct).
The basic prototype-based inheritance mechanism works as follows: Each
QtScript object has an internal link to another object, its
\e{prototype}. When a property is looked up in an object, and the
object itself does not have the property, the property is looked up
in the prototype object instead; if the prototype has the property,
then that property is returned. Otherwise, the property is looked up
in the prototype of the prototype object, and so on; this chain of
objects constitutes a \e{prototype chain}. The chain of prototype
objects is followed until the property is found or the end of the
chain is reached.
For example, when you create a new object by the expression \c{new
Object()}, the resulting object will have as its prototype the
standard \c{Object} prototype, \c{Object.prototype}; through this
prototype relation, the new object inherits a set of properties,
including the \c{hasOwnProperty()} function and \c{toString()}
function:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 27
The \c{toString()} function itself is not defined in \c{o} (since we
did not assign anything to \c{o.toString}), so instead the
\c{toString()} function in the standard \c{Object} prototype is
called, which returns a highly generic string representation of
\c{o} ("[object Object]").
Note that the properties of the prototype object are not \e{copied} to
the new object; only a \e{link} from the new object to the prototype
object is maintained. This means that changes done to the prototype
object will immediately be reflected in the behavior of all objects
that have the modified object as their prototype.
\section2 Defining Classes in a Prototype-Based Universe
In QtScript, a class is not defined explicitly; there is no
\c{class} keyword. Instead, you define a new class in two steps:
\list 1
\i Define a \e{constructor function} that will initialize new objects.
\i Set up a \e{prototype object} that defines the class interface, and
assign this object to the public \c{prototype} property of the
constructor function.
\endlist
With this arrangement, the constructor's public \c{prototype}
property will automatically be set as the prototype of objects created
by applying the \c{new} operator to your constructor function;
e.g., the prototype of an object created by \c{new Foo()} will be the
value of \c{Foo.prototype}.
Functions that don't operate on the \c this object ("static" methods)
are typically stored as properties of the constructor function, not
as properties of the prototype object. The same is true for
constants, such as enum values.
The following code defines a simple constructor function for a class
called \c{Person}:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 28
Next, you want to set up \c{Person.prototype} as your prototype
object; i.e., define the interface that should be common to all
\c{Person} objects. QtScript automatically creates a default
prototype object (by the expression \c{new Object()}) for every
script function; you can add properties to this object, or you can
assign your own custom object. (Generally speaking, any QtScript
object can act as prototype for any other object.)
Here's an example of how you might want to override the
\c{toString()} function that \c{Person.prototype} inherits from
\c{Object.prototype}, to give your \c{Person} objects a more
appropriate string representation:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 29
This resembles the process of reimplementing a virtual function
in C++. Henceforth, when the property named \c{toString} is
looked up in a \c{Person} object, it will be resolved in
\c{Person.prototype}, not in \c{Object.prototype} as before:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 30
There are also some other interesting things we can learn about a
\c{Person} object:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 31
The \c{hasOwnProperty()} function is not inherited from
\c{Person.prototype}, but rather from \c{Object.prototype}, which is
the prototype of \c{Person.prototype} itself; i.e., the prototype
chain of \c{Person} objects is \c{Person.prototype} followed by
\c{Object.prototype}. This prototype chain establishes a \e{class
hierarchy}, as demonstrated by applying the \c{instanceof} operator;
\c{instanceof} checks if the value of the public \c{prototype}
property of the constructor function on the right-hand side is
reached by following the prototype chain of the object on the
left-hand side.
When defining subclasses, there's a general pattern you can use. The
following example shows how one can create a subclass of \c{Person}
called \c{Employee}:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 32
Again, you can use the \c{instanceof} to verify that the
class relationship between \c{Employee} and \c{Person} has been
correctly established:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 33
This shows that the prototype chain of \c{Employee} objects is the
same as that of \c{Person} objects, but with \c{Employee.prototype}
added to the front of the chain.
\section2 Prototype-Based Programming with the QtScript C++ API
You can use QScriptEngine::newFunction() to wrap
native functions. When implementing a constructor function,
you also pass the prototype object as an argument to
QScriptEngine::newFunction().
You can call QScriptValue::construct() to call a constructor
function, and you can use QScriptValue::call() from within a
native constructor function if you need to call a base class
constructor.
The QScriptable class provides a convenient way to implement a
prototype object in terms of C++ slots and properties. Take a look
at the \l{Default Prototypes Example} to see how this is done.
Alternatively, the prototype functionality can be implemented in
terms of standalone native functions that you wrap with
QScriptEngine::newFunction() and set as properties of your prototype
object by calling QScriptValue::setProperty().
In the implementation of your prototype functions, you use
QScriptable::thisObject() (or QScriptContext::thisObject()) to
obtain a reference to the QScriptValue being operated upon; then you
call qscriptvalue_cast() to cast it to your C++ type, and perform
the relevant operations using the usual C++ API for the type.
You associate a prototype object with a C++ type by calling
QScriptEngine::setDefaultPrototype(). Once this mapping is
established, QtScript will automatically assign the correct
prototype when a value of such a type is wrapped in a QScriptValue;
either when you explicitly call QScriptEngine::toScriptValue(), or
when a value of such a type is returned from a C++ slot and
internally passed back to script code by the engine. This means you
\e{don't} have to implement wrapper classes if you use this
approach.
As an example, let's consider how the \c{Person} class from the
preceding section can be implemented in terms of the Qt Script API.
We begin with the native constructor function:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 34
Here's the native equivalent of the \c{Person.prototype.toString}
function we saw before:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 35
The \c{Person} class can then be initialized as follows:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 36
The implementation of the \c{Employee} subclass is similar. We
use QScriptValue::call() to call the super-class (Person) constructor:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 37
The \c{Employee} class can then be initialized as follows:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 38
When implementing the prototype object of a class, you may want to use
the QScriptable class, as it enables you to define the API of your
script class in terms of Qt properties, signals and slots, and
automatically handles value conversion between the Qt Script and C++
side.
\section2 Implementing Prototype Objects for Value-based Types
When implementing a prototype object for a value-based type --
e.g. QPointF -- the same general technique applies; you populate
a prototype object with functionality that should be shared
among instances. You then associate the prototype object with
the type by calling QScriptEngine::setDefaultPrototype(). This
ensures that when e.g. a value of the relevant type is returned
from a slot back to the script, the prototype link of the script
value will be initialized correctly.
When values of the custom type are stored in QVariants -- which Qt
Script does by default --, qscriptvalue_cast() enables you to safely
cast the script value to a pointer to the C++ type. This makes it
easy to do type-checking, and, for prototype functions that should
modify the underlying C++ value, lets you modify the actual value
contained in the script value (and not a copy of it).
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 39
\section2 Implementing Constructors for Value-based Types
You can implement a constructor function for a value-based type
by wrapping a native factory function. For example, the following
function implements a simple constructor for QPoint:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 44
In the above code we simplified things a bit, e.g. we didn't check
the argument count to decide which QPoint C++ constructor to use.
In your own constructors you have to do this type of resolution
yourself, i.e. by checking the number of arguments passed to the
native function, and/or by checking the type of the arguments and
converting the arguments to the desired type. If you detect a problem
with the arguments you may want to signal this by throwing a script
exception; see QScriptContext::throwError().
\section2 Managing Non-QObject-based Objects
For value-based types (e.g. QPoint), the C++ object will be destroyed when
the Qt Script object is garbage-collected, so managing the memory of the C++
object is not an issue. For QObjects, Qt Script provides several
alternatives for managing the underlying C++ object's lifetime; see the
\l{Controlling QObject Ownership} section. However, for polymorphic types
that don't inherit from QObject, and when you can't (or won't) wrap the type
in a QObject, you have to manage the lifetime of the C++ object yourself.
A behavior that's often reasonable when a Qt Script object wraps a C++
object, is that the C++ object is deleted when the Qt Script object is
garbage-collected; this is typically the case when the objects can be
constructed by scripts, as opposed to the application providing the scripts
with pre-made "environment" objects. A way of making the lifetime of the C++
object follow the lifetime of the Qt Script object is by using a shared
pointer class, such as QSharedPointer, to hold a pointer to your object;
when the Qt Script object containing the QSharedPointer is
garbage-collected, the underlying C++ object will be deleted if there are no
other references to the object.
The following snippet shows a constructor function that constructs
QXmlStreamReader objects that are stored using QSharedPointer:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 93
Prototype functions can use qscriptvalue_cast() to cast the \c this object
to the proper type:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 94
The prototype and constructor objects are set up in the usual way:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 95
Scripts can now construct QXmlStreamReader objects by calling the \c
XmlStreamReader constructor, and when the Qt Script object is
garbage-collected (or the script engine is destroyed), the QXmlStreamReader
object is destroyed as well.
\section1 Defining Custom Script Classes with QScriptClass
There are cases where neither the dynamic QObject binding provided
by QScriptEngine::newQObject() or the manual binding provided by
QScriptEngine::newFunction() is sufficient. For example, you might
want to implement a dynamic script proxy to an underlying object;
or you might want to implement an array-like class (i.e. that gives
special treatment to properties that are valid array indexes, and
to the property "length"). In such cases, you can subclass
QScriptClass to achieve the desired behavior.
QScriptClass allows you to handle all property access for a
(class of) script object through virtual get/set property functions.
Iteration of custom properties is also supported through the
QScriptClassPropertyIterator class; this means you can advertise
properties to be reported by for-in script statements and
QScriptValueIterator.
\section1 Error Handling and Debugging Facilities
Syntax errors in scripts will be reported as soon as a script is
evaluated; QScriptEngine::evaluate() will return a SyntaxError object
that you can convert to a string to get a description of the error.
The QScriptEngine::uncaughtExceptionBacktrace() function gives you
a human-readable backtrace of the last uncaught exception. In order
to get useful filename information in backtraces, you should pass
proper filenames to QScriptEngine::evaluate() when evaluating your
scripts.
Often an exception doesn't happen at the time the script is evaluated,
but at a later time when a function defined by the script is actually
executed. For C++ signal handlers, this is tricky; consider the case
where the clicked() signal of a button is connected to a script function,
and that script function causes a script exception when it is handling
the signal. Where is that script exception propagated to?
The solution is to connect to the QScriptEngine::signalHandlerException()
signal; this will give you notification when a signal handler causes
an exception, so that you can find out what happened and/or recover
from it.
In Qt 4.4 the QScriptEngineAgent class was introduced. QScriptEngineAgent
provides an interface for reporting low-level "events" in a script engine,
such as when a function is entered or when a new script statement is
reached. By subclassing QScriptEngineAgent you can be notified of these
events and perform some action, if you want. QScriptEngineAgent itself
doesn't provide any debugging-specific functionality (e.g. setting
breakpoints), but it is the basis of tools that do.
The QScriptEngineDebugger class introduced in Qt 4.5 provides a
\l{Qt Script Debugger Manual}{Qt Script debugger} that can be embedded
into your application.
\section2 Redefining print()
Qt Script provides a built-in print() function that can be useful for
simple debugging purposes. The built-in print() function writes to
standard output. You can redefine the print() function (or add your
own function, e.g. debug() or log()) that redirects the text to
somewhere else. The following code shows a custom print() that adds
text to a QPlainTextEdit.
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 45
The following code shows how the custom print() function may be
initialized and used.
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 46
A pointer to the QPlainTextEdit is stored as an internal property
of the script function itself, so that it can be retrieved when
the function is called.
\section1 Using QtScript Extensions
The QScriptEngine::importExtension() function can be used to load plugins
into a script engine. Plugins typically add some extra functionality to
the engine; for example, a plugin might add full bindings for the Qt
Arthur painting API, so that those classes may be used from Qt Script
scripts. There are currently no script plugins shipped with Qt.
If you are implementing some Qt Script functionality that you want other
Qt application developers to be able to use, \l{Creating QtScript Extensions}
{developing an extension} (e.g. by subclassing QScriptExtensionPlugin) is
worth looking into.
\section1 Internationalization
Since Qt 4.5, Qt Script supports internationalization of scripts by building
on the C++ internationalization functionality (see \l{Internationalization
with Qt}).
\section2 Use qsTr() for All Literal Text
Wherever your script uses "quoted text" for text that will be presented to
the user, ensure that it is processed by the QCoreApplication::translate()
function. Essentially all that is necessary to achieve this is to use
the qsTr() script function. Example:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 82
This accounts for 99% of the user-visible strings you're likely to write.
The qsTr() function uses the basename of the script's filename (see
QFileInfo::baseName()) as the translation context; if the filename is not
unique in your project, you should use the qsTranslate() function and pass a
suitable context as the first argument. Example:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 83
If you need to have translatable text completely outside a function, there
are two functions to help: QT_TR_NOOP() and QT_TRANSLATE_NOOP(). They merely
mark the text for extraction by the \c lupdate utility described below. At
runtime, these functions simply return the text to translate unmodified.
Example of QT_TR_NOOP():
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 84
Example of QT_TRANSLATE_NOOP():
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 85
\section2 Use String.prototype.arg() for Dynamic Text
The String.prototype.arg() function (which is modeled after QString::arg())
offers a simple means for substituting arguments:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 86
\section2 Produce Translations
Once you are using qsTr() and/or qsTranslate() throughout your scripts, you
can start producing translations of the user-visible text in your program.
The \l{Qt Linguist manual} provides further information about
Qt's translation tools, \e{Qt Linguist}, \c lupdate and \c
lrelease.
Translation of Qt Script scripts is a three-step process:
\list 1
\o Run \c lupdate to extract translatable text from the script source code
of the Qt application, resulting in a message file for translators (a TS
file). The utility recognizes qsTr(), qsTranslate() and the
\c{QT_TR*_NOOP()} functions described above and produces TS files
(usually one per language).
\o Provide translations for the source texts in the TS file, using
\e{Qt Linguist}. Since TS files are in XML format, you can also
edit them by hand.
\o Run \c lrelease to obtain a light-weight message file (a QM
file) from the TS file, suitable only for end use. Think of the TS
files as "source files", and QM files as "object files". The
translator edits the TS files, but the users of your application
only need the QM files. Both kinds of files are platform and
locale independent.
\endlist
Typically, you will repeat these steps for every release of your
application. The \c lupdate utility does its best to reuse the
translations from previous releases.
When running \c lupdate, you must specify the location of the script(s),
and the name of the TS file to produce. Examples:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 87
will extract translatable text from \c myscript.qs and create the
translation file \c myscript_la.qs.
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 88
will extract translatable text from all files ending with \c{.qs} in the
\c scripts folder and create the translation file \c scripts_la.qs.
Alternatively, you can create a separate qmake project file that sets up
the \c SOURCES and \c TRANSLATIONS variables appropriately; then run
\c lupdate with the project file as input.
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 89
When running \c lrelease, you must specify the name of the TS input
file; or, if you are using a qmake project file to manage script
translations, you specify the name of that file. \c lrelease will create
\c myscript_la.qm, the binary representation of the translation.
\section2 Apply Translations
In your application, you must use QTranslator::load() to load the
translation files appropriate for the user's language, and install them
using QCoreApplication::installTranslator(). Finally, you must call
QScriptEngine::installTranslatorFunctions() to make the script translation
functions (qsTr(), qsTranslate() and \c{QT_TR*_NOOP()}) available to scripts
that are subsequently evaluated by QScriptEngine::evaluate(). For scripts
that are using the qsTr() function, the proper filename must be passed as
second argument to QScriptEngine::evaluate().
\c linguist, \c lupdate and \c lrelease are installed in the \c bin
subdirectory of the base directory Qt is installed into. Click Help|Manual
in \e{Qt Linguist} to access the user's manual; it contains a tutorial
to get you started.
See also the \l{Hello Script Example}.
\section1 ECMAScript Compatibility
QtScript implements all the built-in objects and properties defined
in the \l{ECMA-262} standard; see the
\l{ECMAScript Reference}{ECMAScript reference} for an overview.
\section1 QtScript Extensions to ECMAScript
\list
\i \c{__proto__} \br
The prototype of an object (QScriptValue::prototype())
can be accessed through its \c{__proto__} property in script code.
This property has the QScriptValue::Undeletable flag set.
For example:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 40
\i \c{Object.prototype.__defineGetter__} \br
This function installs a
getter function for a property of an object. The first argument is
the property name, and the second is the function to call to get
the value of that property. When the function is invoked, the
\c this object will be the object whose property is accessed.
For example:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 41
\i \c{Object.prototype.__defineSetter__} \br
This function installs a
setter function for a property of an object. The first argument is
the property name, and the second is the function to call to set
the value of that property. When the function is invoked, the
\c this object will be the object whose property is accessed.
For example:
\snippet doc/src/snippets/code/doc_src_qtscript.qdoc 42
\i \c{Function.prototype.connect} \br
This function connects
a signal to a slot. Usage of this function is described in
the section \l{Using Signals and Slots}.
\i \c{Function.prototype.disconnect} \br
This function disconnects
a signal from a slot. Usage of this function is described in
the section \l{Using Signals and Slots}.
\i \c{QObject.prototype.findChild} \br
This function is semantically equivalent to QObject::findChild().
\i \c{QObject.prototype.findChildren} \br
This function is semantically equivalent to QObject::findChildren().
\i \c{QObject.prototype.toString} \br
This function returns a default string representation of a QObject.
\i \c{gc} \br
This function invokes the garbage collector.
\i \c{Error.prototype.backtrace} \br
This function returns a human-readable backtrace, in the form of
an array of strings.
\i Error objects have the following additional properties:
\list
\i \c{lineNumber}: The line number where the error occurred.
\i \c{fileName}: The file name where the error occurred (if a file name
was passed to QScriptEngine::evaluate()).
\i \c{stack}: An array of objects describing the stack. Each object has
the following properties:
\list
\i \c{functionName}: The function name, if available.
\i \c{fileName}: The file name, if available.
\i \c{lineNumber}: The line number, if available.
\endlist
\endlist
\endlist
*/
|