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

  • The wrapper is created when the QObject is first exposed as a lua value through a Value object.

  • A delete flag is carried by the wrapper.

  • The wrapper will delete the associated QObject when garbage collected only if its delete flag is set.

  • The delete flag is set on wrapper creation only if the QObject has a parent with the delete flag set.

  • The delete flag can be updated from C++ code using the Value::Value constructor.

  • The wrapper can become void/empty if the associated QObject get destroyed.

New QObject wrappers returned by the QtLib lua library functions 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);

// Reuse same wrapper as dialog1 and explicitly leave ownership
state["dialog3"] = QtLua::Value(state, qd, false);

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

3.4.2 Dynamic signals and slots  

Qt signals and slots connections can be managed dynamically from lua script. Moreover a Qt signal can be connected directly to a lua function.

The qt.connect lua function can be used to connect a Qt slot either to a Qt signal or to a lua function:

-- connect signal and slot of given Qt objects
qt.connect(qobjectwrapper1, "qt_signal_name", qobjectwrapper2, "qt_slot_name")

-- connect slot to given lua function
qt.connect(qobjectwrapper, "qt_signal_name", lua_function)

When a lua function is called from a Qt signal, its first argument is the sender object and following arguments are converted signal parameters (see Qt/Lua types conversion).

The qt.disconnect lua functions can be used to disconnect a Qt slot:

-- disconnect signal and slot of given Qt objects
qt.disconnect(qobjectwrapper1, "qt_signal_name", qobjectwrapper2, "qt_slot_name")

-- disconnect signal from given lua function
qt.disconnect(qobjectwrapper, "qt_signal_name", lua_function)

-- disconnect signal from all connected lua functions
qt.disconnect(qobjectwrapper, "qt_signal_name")

Valid XHTML 1.0 StrictGenerated by diaxen on Mon Aug 15 03:23:06 2011 using MkDoc