Embedding lqt

Skip to first unread message

Michal Kottman

Jun 14, 2012, 9:18:09 AM6/14/12
to Paul Nispel, lqt-bi...@googlegroups.com
On 13 June 2012 20:39, Paul Nispel <pni...@gmail.com> wrote:
> Hi,

Hello, I am CC-ing this to the lqt mailing list as it may help some
people, hope you don't mind.

> I'm attempting to write an application that uses Qt scripting in Lua but am having problems figuring out how to pass an object from my C++ code to Lua that lqt can use like a normal object that was created in Lua by lqt. If anything like this is possible, please let me know.

lqt is meant more for "main application development" than for
embedding, but I am certain you could get that working. First, try to
look at QtLua [1] if it suits your purpose.

If you really require full binding, then lqt is what you are looking
for and you could do is this:

1) Create a CMake build directory and run CMake:
$ mkdir /path/to/build; cd /path/to/build; cmake /path/to/lqt

2) Generate the source code (replace qtcore with any module you wish
to bind, make sure to watch dependendcies)
$ make generate_qtcore_cpp

3) Embed the generated sources into your project, they will be stored
at /path/to/build/qtcore_src/

Now, there are two ways you would want to use Qt objects generated by
your application in Lua:

1) You just want to pass the objects so that Lua could use its methods.
2) You want the object to be extended in Lua, i.e. you want to
override virtual methods and define custom signals/slots.

Use case 1 is relatively easy - you can use the following function
from common/lqt_common.cpp:
void lqtL_pushudata (lua_State *L, const void *p, const char *name);

This will push a "blessed boxed pointer" with the type "name". The
type has to be the type name under which the type is recognized by
lqt, and it should look like "QObject*", i.e.:

QObject *o = new QObject;
lqtL_pushudata(L, o, "QObject*");

This will push the object to the stack and make it usable as a pointer
to QObject in Lua.

The second use case is more complicated. Overriding and signals/slots
require some setup from lqt before it can be used in Lua. For this,
you have to find the binding constructors for the objects you want to
create. As I said, lqt was not primarily meant for embedding, so this
is going to be a little rough.

Each class has a pair of files, header and source. Let's say you want
to use QObject from your source. One way to create the object is to
actually look up the Lua table for QObject and call the new()
function, or call the class directly to have a GC-collected object:

lua_getglobal(L, "QObject");
// push constructor arguments, none in this case
lua_call(L, -1);

The alternative is to directly call the binding. The binding is stored
in qtcore_src/qtcore_head_QObject.hpp and
qtcore_src/qtcore_meta_QObject.cpp . When you open the C++ source
file, look for this:

static luaL_Reg lqt_metatable_5590[] = {
{ "startTimer", lqt_dispatcher_startTimer_5590 },
{ "deleteLater", lqt_dispatcher_deleteLater_5590 },
{ "dynamicPropertyNames", lqt_dispatcher_dynamicPropertyNames_5590 },
{ "new", lqt_dispatcher_new_5590 },

As you can see, the constructor for QObject is implemented in
lqt_dispatcher_new_5590. It is a Lua C functions, which means that its
signature is:

static int lqt_dispatcher_new_5590 (lua_State *L);

Notice the static - this means you cannot call it outside of the file.
Either remove the "static", or change the binding generator not to use
it here:

./generator/classes.lua-695- for n, l in pairs(methods) do
./generator/classes.lua-696- local name = operators.rename_operator(n)
./generator/classes.lua:697: local disp = 'static int
lqt_dispatcher_'..name..c.xarg.id..' (lua_State *L) {\n'
./generator/classes.lua-698- local testcode = {}
./generator/classes.lua-699- for tc, f in pairs(l) do

Now you can call it like you would in Lua case using lua_pushcfunction
and lua_call.

So, this are a few steps to try out. As I said several times, lqt was
not designed primarily for embedding.

[1] http://www.nongnu.org/libqtlua/
Reply all
Reply to author
0 new messages