27

I'm adding scripting with Lua to an application of ours, and I need to implement bindings for the GUI-toolkit. The toolkit we use is wxWidgets.

I'm using Lua 5.1 and luabind 0.9.1, and it has worked very well so far. However, I'm not sure how to best handle events. For example, if you want to create a button and print a string when it is clicked, you write something like this in C++

class MyClass : public wxFrame
{
    MyClass (...)
    {
        b = new wxButton (this, -1, "Click me");
        b->Bind (wxEVT_COMMAND_BUTTON_CLICKED, &MyClass::HandleButtonClick, this);
    }

    void HandleButtonClick (wxCommandEvent& ev)
    {
        wxMessageBox ("You clicked me");
    }
}

My dream-API for doing the same thing in Lua would look something like this:

b = wx.Button (frm, -1, "Click me")
b.on_click = function (ev)
    print ("Button clicked")
end

Or, allowing multiple event handlers:

b.on_click:add (function (ev)
    print ("Button clicked again ...")
end)

If not possible, something like this which more resembles the C++ API:

b.bind (wx.EVT_COMMAND_BUTTON_CLICKED, function (ev)
    print ("Yet again")
end)

However, I'm not sure how to implement this using Luabind without writing a wrapper class for every class in the wxWidgets-library that I want to use.

Any suggestions?

Could perhaps Luabind create helper classes (say "wxLuaEventPropagator") automatically in some way? So that the wxButton class has a nested wxLuaEventPropagator-class for each event ("on_click", and so on). Once again, i do not want to create wrapper classes for every class in wxWidgets that I use, since there is a ton.

(Yes, I'm aware of wxLua)

Jonatan
  • 3,752
  • 4
  • 36
  • 47
  • You say you're aware of wxLua - so why not use it? – John Zwinck Apr 10 '11 at 15:35
  • 1
    Because: 1. the wx-part will not be much used by scripts, and i think it's a quite heavy dependency (not necessarily so though), 2. the project might move to another gui toolkit in the not too distant future, and most importantly: 3. there are other api's i will have to wrap as well, so i still have to find a solution for this. My current plan is to abandon Luabind, although I like it very much, and use SWIG instead. – Jonatan Apr 11 '11 at 10:27
  • You mentioned C++. Is your host application written in C++? – Jonathan Swinney May 13 '11 at 02:43
  • I wasn't familiar with luabind. After some research, I answered my own question. – Jonathan Swinney May 13 '11 at 02:49
  • wrong Jonathan... I have been thinking about the question and may answer it if I come up with something novel. – Jonathan Swinney May 19 '11 at 12:03

1 Answers1

2

You can use luabind::object to do that.

An exemple class : class MyClass { public: void OnMouseMoved(int x, int y); void SetEventFunction(const luabind::object &fn);

private:
    luabind::object m_eventFunction;
};


void MyClass::SetEventFunction(const luabind::object &fn)
{
    if(luabind::type(fn) == LUA_TFUNCTION)
    {
        cout << "A function" << endl;
        m_eventFunction = fn;
    }
    else
    {
        cout << "Not a function" << endl;
    }
}

void MyClass::OnMouseMoved(int x, int y)
{
    if(m_eventFunction.is_valid())
    {
        luabind::call_function<void>(m_eventFunction, x, y);
    }
}

In lua code, it would be :

myClass = MyClass()

myClass:SetEventFunction( function (x, y)
    print ("The new mouse position is", x, y)
end)

To had more than one function to an event, you can use std::vector of luabind::object

Congelli501
  • 2,403
  • 2
  • 27
  • 28
  • Since the classes are part of a 3rd party library I would have to wrap each and every class using this method. As I commented above, I'm using SWIG now instead, as it allows you to extend classes in a simple way. – Jonatan May 27 '11 at 07:27