Merge pull request #52 from gogoprog/patch-1
[lqt/mk.git] / doc / USAGE.md
blob3ea71c251cb7f5f3b52689722787c01faf2acc8e
1 Overview of lqt
2 ===============
4 This document explains how to use lqt in Lua, how to load the libraries, how to use them, create instances and use advanced features.
6 Loading the library
7 -------------------
9 The libraries are distributed as separate modules, that can be loaded by the `require` function. They are named by lowercasing the module name, i.e. `qtcore`, `qtgui`, `qtxml`, etc.:
11     require 'qtcore'
13 Classes and creating instances
14 ------------------------------
16 Classes are named the same as in Qt (i.e. `QPushButton`), and are registered in the global table. To create an instance, you can either "call" the class, or call the `new()` function. More about memory management later.
18 You can simply pass the arguments as parameters.
20     a = QPushButton.new("Button A")
21     b = QPushButton("Button B")
23 Calling methods
24 ---------------
26 Calling methods follows the Lua idioms - you pass the object as the first parameter, so you can use the colon:`btn:setVisible(true)`. For static methods, you can use the dot: `QApplication.exec()`.
28 Mapping of types
29 ----------------
31 ### Primitives
33 Primitive C++ types, like `int`, `bool`, `double`, `const char *` are converted to corresponding Lua types and vice-versa.
35 ### Classes
37 Every class and struct is represented by a userdata containing a boxed pointer to the object. To get the type of an object, look at `obj.__type`, which is a string with the name of the class (the key of it's metatable in registry).
39 One exception is QByteArray - it is mapped directly into Lua string, and you can pass Lua string anywhere QByteArray is accepted. You lose ability to call methods of the QByteArray, but you can do most of the functionality in Lua anyway. Why can you pass Lua string where QString is expected? lqt uses the same principle as C++ - implicit constructors. Becase QString can be constructed from a QByteArray (which is Lua string), you can pass a Lua string wherever a QString is expected. This also means that you can pass number/boolean/string as QVariant parameter, etc.
41 ### Enums
43 The Qt API consistently uses named enums. This makes it possible to recognize what values are needed for an enum. For example, the method `void QWidget::setFocus(Qt::FocusReason reason)` is available in Lua as `QWidget:setFocus(reason)`, where you can specify `reason` in two ways:
45 * using string - `'MouseFocusReason'`, `'TabFocusReason'`, etc.
46 * using the enum name and value name in the Qt table - `Qt.FocusReason.MouseFocusReason`, `Qt.FocusReason.TabFocusReason`, etc.
48 If more than one enum value can be supplied (i.e. for flags), you can specify the strings as a table, like `textEdit:setTextInteractionFlags {'TextSelectableByMouse', 'TextSelectableByKeyboard'}`, or you can add the numerical values using `+`.
50 Memory management
51 -----------------
53 Memory management with Lua and C++ is a non-trivial issue. For every bound class, lqt provides the `new(...)` and `delete(o)` methods. `new(...)` creates a new instance, with `...` being the constructor parameters, and `delete(o)` frees the memory and sets the boxed pointer to NULL.
55 Mix in Lua garbage collector (GC). By default, lqt does not let the Lua GC free the created objects. However, you can do this:
57     local o = QObject.new()
58     o.__gc = o.delete -- Lua takes ownership of the object
60 This way, when Lua collects the userdata, it will also free the allocated object. lqt provides a shortcut for this - you can call the class directly to create an object owned by Lua:
62     local o = QObject() -- will be garbage collected when not referenced
64 This relates somewhat to C++ - `QObject.new()` creates a "long living" object, `QObject()` creates a temporary object which will be freed when not necessary.
66 Whenever `o` goes out of scope (and there is no other reference to it), the object will be eventually freed by the GC. You have to be careful however - if Qt keeps a reference to an object, and there is no reference to it in Lua, the GC may collect it and free the memory, and then cause a segmentation fault when Qt accesses it. To prevent such errors, keep a reference to it while it may be needed, for example in a table which is kept alive: `t[obj]=true`.
68 The Qt framework also provides an alternative way - the parent/child mechanism. Every class derived from QObject has a constructor that takes an argument named `parent` (check the Qt documentation). The object then becomes a child of `parent`, and is freed whenever the parent gets freed. When using the parent/child system, you cannot use the Lua GC (because the object will be freed twice).
70 Essentially you have 3 choices, and can mix freely between them:
72 * forget about memory management and use `new(...)` everywhere - not good for long-running apps, since it eats up memory that is never freed, however works well for small static applications
73 * use `new_local(...)` and keep references to objects while they are used by Qt - the preferred way, Lua takes care of memory management
74 * create a widget/parent object and create other objects as it's children using `new(..., parent)` - the children will be deleted automatically with the parent
76 Additional Lua fields
77 -----------------
79 The userdata objects can also serve as traditional Lua tables (these are stored in the userdata's environment table):
81     local obj = QObject.new()
82     obj.message = "Hello from Lua!"
84 lqt keeps references to objects keyed by their pointer (in a weak table). When you have a userdata and you keep a reference to it, and a method returns the same pointer as return value, or it is passed to your callback function, you get back the same userdata (along with it's Lua fields).
86 Virtual methods
87 ---------------
89 You can override a virtual method and implement abstract methods in Lua. To do that, you need to save them as an object field. Easier to show on code:
91     wnd = QMainWindow()
92     function wnd:resizeEvent(e)
93         print("I'm being resized!")
94     end
95     wnd:show()
97 Signal/slot mechanism
98 ---------------------
100 To see the signals and slots an object responds to, you can retrieve a list of them by using the `__methods()` method. It returns a table of strings, representing the signatures and types of Qt "methods" (= signals and slots) it supports.
102 To connect signals and slots, use the standard `connect()` method, you just have to prepend '2' to the signal signature, and '1' to the slot signature. If you really want, you can use the following functions:
104     function SIGNAL(sig) return '2'..sig end
105     function SLOT(sig) return '1'..sig end
107 To implement custom slots, you need to use the `__addmethod(obj, sig, func)` method to add a custom slot. You can implement it on any object you want, but it usually makes sense to implement it directly on the provider of the signal. It is used as follows:
109     local btn = QCheckButton("Press me!")
110     btn:__addmethod("mySlot(bool)", function(self, state)
111         print("My state is", state)
112     end)
113     btn:connect('2toggled(bool)', btn, '1mySlot(bool)')
115 You can also use a function directly as the slot handler (which does the above automatically):
117     local btn2 = QCheckButton("Press me again!")
118     btn2:connect('2toggled(bool)', function(self, state)
119         print("My state is", state)
120     end)
122 You have to be careful about the signature (Qt is picky, you have to be precise). Always check `__methods()` to see the correct signature: `table.foreachi(obj:__methods(), print)`. Also, lqt can only implement slots of known signature - they are compiled from the list of all signals, therefore you can create a slot for any signal signature present in Qt, but you cannot create new slots/signals (use pure Lua workarounds for that).
124 The Qt API
125 ------------
127 For reference on available classes and their methods, please refer to the [Qt documentation](http://doc.qt.nokia.com/). lqt provides essentially the same API, except that you do not need differentiate between pointers, references and values.