3.4 QObject wrapping
Wrapping of QObject objects allows use of Qt widgets and objects from lua.
QtLua heavily takes advantage of the Qt meta object system to expose all QObjects signals, slots, enums, properties and child objects to lua script.
See The qtlua interpreter section for examples of QObject manipulation from lua script.
3.4.1 QObject ownership
Lua uses a garbage collector to track references to live values and QtLua provides the Ref smart pointer class to track references to UserData based objects, but Qt doesn't provide a way to track every pointer to QObject objects.
QObject objects are seen from lua has an userdata value which provides access to child objects and to Qt meta fields like methods, properties... This userdata value is an internal UserData based wrapper with a pointer to the actual QObject.
We have no way to know if C++ pointers to the wrapped QObject exist or if the wrapper will be the single owner. Unfortunately we still have to take the right action when the wrapper get garbage collected.
The following rules apply:
There is a single wrapper instance for a given QObject instance. This wrapper is created when the QObject is first exposed as a lua value through a Value object. It lasts as long as the QObject exists or a lua reference to the wrapper exists. The wrapper will become void/empty if the associated QObject is deleted by C++ code.
A delete flag is carried by the wrapper. The wrapper will delete the associated QObject when no more lua reference to the wrapper exist only if the delete flag is set and the QObject has no parent.
The delete flag is set on wrapper creation only if the QObject has a parent. The delete flag can be updated from C++ code using the Value::Value constructor.
New QObject wrappers returned by the functions in the qt Lua library have their delete flag set.
A reparent flag is also available to allow or deny parent change for a QObject.
The example below shows how QObject ownership is handled in C++ code:
// code from examples/cpp/qobject/qobject_owner.cc:30
QApplication app(argc, argv);
QtLua::State state;
QDialog *qd = new QDialog();
// Assume C++ pointers to QDialog exist as it has no parents, do not take ownership
state["dialog1"] = qd;
// Explicitly take ownership of new QDialog
state["dialog2"] = QtLua::Value(&state, new QDialog(), true, true);
// Reuse same wrapper as dialog1 and explicitly leave ownership
state["dialog3"] = QtLua::Value(&state, qd, false, true);
// Invoke QDialog show() methods from lua
state.exec_statements("dialog1:show(); dialog2:show();");
app.exec();
// Delete qd QObject, dialog1 and dialog3 now refer to an empty wrapper
delete qd;
// Delete wrapper and associated QObject
state.exec_statements("dialog2 = nil");