27
votes

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)

1
You say you're aware of wxLua - so why not use it? - John Zwinck
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
You mentioned C++. Is your host application written in C++? - Jonathan Swinney
I wasn't familiar with luabind. After some research, I answered my own question. - Jonathan Swinney
wrong Jonathan... I have been thinking about the question and may answer it if I come up with something novel. - Jonathan Swinney

1 Answers

2
votes

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