话接上篇。经过前几篇博客,咱们实如今Lua脚本中执行Qt类中函数的方法,以及在Lua脚本中链接Qt对象的信号与槽。ide
可是,咱们也能发现,若是但愿在Lua脚本中执行Qt类的函数,就必须绑定一个真正实现功能的函数。如QWidget::show(),须要写一个在栈中取出widget指针,widget调用show()函数的方式。若是但愿在Lua中调用大量函数,就须要编写大量的C++实现函数。有没有什么省时省力的好方法呢?函数
上一篇中咱们实现了在Lua脚本中链接信号与槽。咱们只是传过去了两个QObject的对象,和两个字符串的函数名。咱们并无具体实现那个函数,可是槽函数顺利执行了。这给了笔者启发。若是我传过去一个函数名,理论上我能够找一个信号链接并激发它,也就达到了执行的目的。测试
OK,咱们写这样一个函数:lua
static int exec(lua_State *state) { QObject* obj = (QObject* )tolua_tousertype(state, 1, 0); const char * slot = tolua_tostring(state, 2, 0); if(obj != NULL) { RunSLOT run; QObject::connect(&run, SIGNAL(sendSignal()), obj, QString("1%0()").arg(slot).toLocal8Bit().data()); } return 1; }
取得QObject对象,以及字符串的槽函数名称。而后咱们新建了一个RunSLOT对象,链接了run和obj对象。这样就能执行字符串表明的函数?spa
继续看RunSLOT类:指针
#ifndef RUNSLOT_H #define RUNSLOT_H #include <QObject> class RunSLOT : public QObject { Q_OBJECT public: RunSLOT(QObject *parent = 0); ~RunSLOT(); signals: void sendSignal(); }; #endif // RUNSLOT_H
#include "runslot.h" RunSLOT::RunSLOT(QObject *parent) : QObject(parent) { } RunSLOT::~RunSLOT() { emit sendSignal(); }
在析构是发出sendSignal信号,激发槽函数。而RunSLOT类对象run在遇到‘}’自动析构(C++局部变量原则),也就间接的执行了槽函数。code
在绑定函数时将exec绑定到类里,而后写个测试脚本看看:对象
widget = QWidget:new() widget:exec("show") button = QPushButton:new() button:exec("show") connect(button, "clicked()", widget, "hide()")
成功显示一个窗体,一个按钮。blog
完整main.cpp以下:资源
// own #include "include/lua.hpp" #include "qlua.h" #include "runslot.h" // qt #include <QWidget> #include <QApplication> #include <QFile> #include <QDebug> 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()); return 1; } static int exec(lua_State *state) { QObject* obj = (QObject* )tolua_tousertype(state, 1, 0); const char * slot = tolua_tostring(state, 2, 0); if(obj != NULL) { RunSLOT run; QObject::connect(&run, SIGNAL(sendSignal()), obj, QString("1%0()").arg(slot).toLocal8Bit().data()); } return 1; } static int QObject_delete(lua_State* state) { qDebug() << "delete Start"; QObject* obj = (QObject* )tolua_tousertype(state, 1, 0); if(NULL != obj) { qDebug() << "delete~"; delete obj; } return 1; } static int QWidget_new(lua_State* state) { QWidget* widget = new QWidget(); tolua_pushusertype(state, widget, "QWidget"); return 1; } static int QPushButton_new(lua_State* state) { QPushButton* button = new QPushButton(); tolua_pushusertype(state, button, "QPushButton"); return 1; } static int QWidget_resize(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; } int main(int argc, char * argv[]) { Q_INIT_RESOURCE(resources); QApplication a(argc, argv); QLua lua; lua.beginModule(""); lua.addType("QWidget", QObject_delete); lua.moduleTypeFunction("new", QWidget_new); lua.moduleTypeFunction("resize", QWidget_resize); lua.moduleTypeFunction("exec", exec); lua.endModule(); lua.addType("QPushButton", QObject_delete); lua.moduleTypeFunction("new", QPushButton_new); lua.moduleTypeFunction("exec", exec); lua.endModule(); lua.endModule(); lua.pushFunction("connect", connect); // 读取资源文件 QFile file("../../LuaTest/test.lua"); file.open(QIODevice::ReadOnly | QIODevice::Text); QTextStream in(&file); in.setCodec("UTF-8"); // 执行 lua.run(in.readAll()); return a.exec(); }
咱们能够在将绑定exec函数写在QLua类里,添加类时就绑定这个函数。
固然,这个方法的局限性在于执行的函数无参数,并且必须是槽函数。若是想自由一个,能够在调用时写上参数,参数类型,C++这边判断并选择不一样的信号链接方式,一劳永逸。
经过这个例子,咱们能够发现,Qt自己就具有由字符串执行函数的能力,按照个人看法,这就是一种半动态。笔者会继续作下去,由于这个真的颇有趣。
完整例程代码下载:http://pan.baidu.com/s/1sjFDiRb