首页 > 代码库 > Win32下 Qt与Lua交互使用(三):在Lua脚本中connect Qt 对象

Win32下 Qt与Lua交互使用(三):在Lua脚本中connect Qt 对象

    话接上文。笔者为了方便使用Lua,自己编写了一个Lua的类。主要代码如下:

    QLua.h

 1 #ifndef QLUA_H 2 #define QLUA_H 3  4 // own 5 #include "include/lua.hpp" 6  7 // qt 8 #include <QObject> 9 #include <QFile>10 #include <QDebug>11 12 #include <QWidget>13 #include <QLineEdit>14 #include <QPushButton>15 #include <QMessageBox>16 17 class QLua : public QObject18 {19     Q_OBJECT20 public:21     QLua(QObject *parent = 0);22     ~QLua();23 24     // lua25     void init();26     void close();27 28     void pushFunction(QString funcName, lua_CFunction func);29 30     void beginModule(QString);31     void addType(QString, lua_CFunction deleteFunc);32     void moduleTypeFunction(QString, lua_CFunction);33     void endModule();34 35     void run(QString);36 signals:37 38 public slots:39 40 private:41     lua_State *luaState;42 43     bool isStartModule;44 };45 46 #endif // QLUA_H

    QLua.cpp

 1 #include "qlua.h" 2  3 QLua::QLua(QObject *parent) : 4     QObject(parent) 5   , luaState(NULL) 6   , isStartModule(false) 7 { 8     init(); 9 }10 11 QLua::~QLua()12 {13     close();14 }15 16 void QLua::init()17 {18     luaState = luaL_newstate();19     luaL_openlibs(luaState);20 }21 22 void QLua::close()23 {24     if(luaState != NULL)25     {26         lua_close(luaState);27         luaState = NULL;28     }29 }30 31 void QLua::pushFunction(QString funcName, lua_CFunction func)32 {33     if (funcName.isEmpty()) return;34     if (func == NULL)       return;35 36     lua_pushcfunction(luaState, func);37     lua_setglobal(luaState, funcName.toLocal8Bit().data());38 }39 40 void QLua::beginModule(QString name)41 {42     if(luaState == NULL) return;43 44     if (isStartModule == false)45     {46         tolua_open(luaState);47         tolua_module(luaState, NULL, 0);48         isStartModule = true;49     }50 51     const char *str = name.isEmpty()? NULL : name.toLocal8Bit().data();52     tolua_beginmodule(luaState, str);53 }54 55 void QLua::addType(QString name, lua_CFunction deleteFunc)56 {57     if (luaState == NULL) return;58     if (name.isEmpty())   return;59     if (deleteFunc == NULL) return;60 61     tolua_usertype(luaState, name.toLocal8Bit().data());62     const char *str = name.toLocal8Bit().data();63     tolua_cclass(luaState, str, str, "", deleteFunc);64     beginModule(name);65 }66 67 void QLua::moduleTypeFunction(QString name, lua_CFunction func)68 {69     if(luaState == NULL) return ;70     if (name.isEmpty())  return;71 72     const char *str = name.toLocal8Bit().data();73     tolua_function(luaState, str, func);74 }75 76 void QLua::endModule()77 {78     tolua_endmodule(luaState);79 }80 81 void QLua::run(QString str)82 {83     luaL_loadbuffer(luaState, str.toLocal8Bit().data(), str.length(), "line");84     lua_pcall(luaState, 0, 0, 0);85 }

 

    QLua类可以方便的实现一些简单的Lua操作,如初始化,关闭,运行Lua代码,绑定函数等。

 

    笔者目前想做到的是能在Lua代码中自有的生成Qt对象,然后能连接Qt原生对象的信号与槽。那么如何实现呢?

    Qt中连接信号与槽的函数是QObject::connect(QObject * a, SIGNAL(), QObject * b, SLOT())。首先,我们要弄清楚SIGNAL和SLOT到底是什么。

    从connect的参数列表中,我们可以很清晰的看到SIGNAL和SLOT的结果都是char*类型的字符串。我们可以直接在SIGNAL上点右键,转到SIGNAL的定义。或者做个简单的实验。测试如下Qt代码:

    qDebug() << QString::fromLocal8Bit(SIGNAL(clicked()));    qDebug() << QString::fromLocal8Bit(SLOT(close()));

    得到的结果很有意思:

"2clicked()" "1close()" 

    简单总结就是我们只要传入函数名的字符串,加上前缀即可。SIGNAL的前缀是2,SLOT的前缀是1。

    这样我们就可以实现在Lua中的connect函数了。仍在使用C++编写,然后绑定到Lua里。如下:

 1 static int connect(lua_State* state) 2 { 3     QObject * a = (QObject*)tolua_tousertype(state, 1, 0); 4     const char * signal = tolua_tostring(state, 2, 0); 5     QObject * b = (QObject*)tolua_tousertype(state, 3, 0); 6     const char * slot = tolua_tostring(state, 4, 0); 7  8     QObject::connect(a, QString("2%0").arg(signal).toLocal8Bit().data(), 9                      b, QString("1%0").arg(slot).toLocal8Bit().data());10 }

    绑定时可以使用上面的QLua类:

lua.pushFunction("connect", connect);

 

    完整main.cpp代码如下:

#include "include/lua.hpp"#include "qlua.h"#include <QWidget>#include <QApplication>#include <QFile>#include <QDebug>static int test(lua_State* state){    QPushButton* a = (QPushButton*)tolua_tousertype(state, 1, 0);    if(a)        a->show();}static int connect(lua_State* state){    QObject * a = (QObject*)tolua_tousertype(state, 1, 0);    const char * signal = tolua_tostring(state, 2, 0);    QObject * b = (QObject*)tolua_tousertype(state, 3, 0);    const char * slot = tolua_tostring(state, 4, 0);    QObject::connect(a, QString("2%0").arg(signal).toLocal8Bit().data(),                     b, QString("1%0").arg(slot).toLocal8Bit().data());}static int tolua_new_QWidget(lua_State* state){    QWidget* widget = new QWidget();    tolua_pushusertype(state, widget, "QWidget");    return 1;}static int tolua_delete_QWidget(lua_State* state){    qDebug() << "delete Start";    QWidget* widget = (QWidget* )tolua_tousertype(state, 1, 0);    if(NULL != widget)    {        qDebug() << "delete~";        widget->close();        delete widget;    }    return 1;}static int tolua_Show_QWidget(lua_State* state){    QWidget* widget = (QWidget* )tolua_tousertype(state, 1, 0);    if(widget != NULL)    {        widget->show();    }    return 1;}static int tolua_new_QPushButton(lua_State* state){    QPushButton* button = new QPushButton();    tolua_pushusertype(state, button, "QPushButton");    return 1;}static int tolua_delete_QPushButton(lua_State* state){    QPushButton* button = (QPushButton* )tolua_tousertype(state, 1, 0);    if(NULL != button)    {        button->close();        delete button;    }    return 1;}static int tolua_Show_QPushButton(lua_State* state){    QPushButton* button = (QPushButton* )tolua_tousertype(state, 1, 0);    if(button != NULL)    {        button->show();    }    return 1;}static int tolua_setText_QPushButton(lua_State* state){    QPushButton* button = (QPushButton* )tolua_tousertype(state, 1, 0);    const char * text = tolua_tostring(state, 2, 0);    if(button != NULL)    {        button->setText(QString::fromLocal8Bit(text));    }    return 1;}static int tolua_Resize_QWidget(lua_State* state){    QWidget* widget = (QWidget* )tolua_tousertype(state, 1, 0);    double a = tolua_tonumber(state, 2, 0);    double b = tolua_tonumber(state, 3, 0);    if(widget)    {        widget->resize((int)a, (int)b);    }    return 1;}static int QApplication_instance(lua_State* state){    tolua_pushusertype(state, QApplication::instance(), "QApplication");    return 1;}static int QApplication_quit(lua_State* state){    QApplication * app = (QApplication *)tolua_tousertype(state, 1, 0);    if(app)        app->quit();    return 1;}static int QApplication_delete(lua_State*){    return 1;}int main(int argc, char * argv[]){    Q_INIT_RESOURCE(resources);    QApplication a(argc, argv);    QLua lua;    lua.beginModule("");    lua.addType("QWidget", tolua_delete_QWidget);    lua.moduleTypeFunction("new", tolua_new_QWidget);    lua.moduleTypeFunction("show", tolua_Show_QWidget);    lua.moduleTypeFunction("resize", tolua_Resize_QWidget);    lua.endModule();    lua.addType("QPushButton", tolua_delete_QPushButton);    lua.moduleTypeFunction("new", tolua_new_QPushButton);    lua.moduleTypeFunction("show", tolua_Show_QPushButton);    lua.moduleTypeFunction("setText", tolua_setText_QPushButton);    lua.endModule();    lua.addType("QApplication", QApplication_delete);    lua.moduleTypeFunction("instance", QApplication_instance);    lua.moduleTypeFunction("quit", QApplication_quit);    lua.endModule();    lua.endModule();    lua.pushFunction("test", test);    lua.pushFunction("connect", connect);    // 读取资源文件    QFile file("://test.lua");    file.open(QIODevice::ReadOnly | QIODevice::Text);    QTextStream in(&file);    in.setCodec("UTF-8");    // 执行    lua.run(in.readAll());    return a.exec();}

    test.lua代码如下:

widget = QWidget:new()widget:show()button = QPushButton:new()button:setText("China")button:show()connect(button, "clicked()", widget, "close()")connect(button, "clicked()", button, "close()")print("run over")

    程序运行结果如下:

    点击China按钮,button和widget的窗口都会关闭。

    至此,已经实现了连接 Qt 对象的信号与槽。

    如果继续做下去,完全可以实现在Lua脚本中使用Qt的类和对象,写出Lua的Gui程序。

    附完整代码工程文件:http://pan.baidu.com/s/1ntmFdjj

    附个偶的博客地址:http://www.cnblogs.com/IT-BOY/

Win32下 Qt与Lua交互使用(三):在Lua脚本中connect Qt 对象