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

时间:2023-03-12 11:20:02

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

QLua.h

 #ifndef QLUA_H
#define QLUA_H // own
#include "include/lua.hpp" // qt
#include <QObject>
#include <QFile>
#include <QDebug> #include <QWidget>
#include <QLineEdit>
#include <QPushButton>
#include <QMessageBox> class QLua : public QObject
{
Q_OBJECT
public:
QLua(QObject *parent = );
~QLua(); // lua
void init();
void close(); void pushFunction(QString funcName, lua_CFunction func); void beginModule(QString);
void addType(QString, lua_CFunction deleteFunc);
void moduleTypeFunction(QString, lua_CFunction);
void endModule(); void run(QString);
signals: public slots: private:
lua_State *luaState; bool isStartModule;
}; #endif // QLUA_H

QLua.cpp

 #include "qlua.h"

 QLua::QLua(QObject *parent) :
QObject(parent)
, luaState(NULL)
, isStartModule(false)
{
init();
} QLua::~QLua()
{
close();
} void QLua::init()
{
luaState = luaL_newstate();
luaL_openlibs(luaState);
} void QLua::close()
{
if(luaState != NULL)
{
lua_close(luaState);
luaState = NULL;
}
} void QLua::pushFunction(QString funcName, lua_CFunction func)
{
if (funcName.isEmpty()) return;
if (func == NULL) return; lua_pushcfunction(luaState, func);
lua_setglobal(luaState, funcName.toLocal8Bit().data());
} void QLua::beginModule(QString name)
{
if(luaState == NULL) return; if (isStartModule == false)
{
tolua_open(luaState);
tolua_module(luaState, NULL, );
isStartModule = true;
} const char *str = name.isEmpty()? NULL : name.toLocal8Bit().data();
tolua_beginmodule(luaState, str);
} void QLua::addType(QString name, lua_CFunction deleteFunc)
{
if (luaState == NULL) return;
if (name.isEmpty()) return;
if (deleteFunc == NULL) return; tolua_usertype(luaState, name.toLocal8Bit().data());
const char *str = name.toLocal8Bit().data();
tolua_cclass(luaState, str, str, "", deleteFunc);
beginModule(name);
} void QLua::moduleTypeFunction(QString name, lua_CFunction func)
{
if(luaState == NULL) return ;
if (name.isEmpty()) return; const char *str = name.toLocal8Bit().data();
tolua_function(luaState, str, func);
} void QLua::endModule()
{
tolua_endmodule(luaState);
} void QLua::run(QString str)
{
luaL_loadbuffer(luaState, str.toLocal8Bit().data(), str.length(), "line");
lua_pcall(luaState, , , );
}

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里。如下:

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

绑定时可以使用上面的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, , );
if(a)
a->show();
} static int connect(lua_State* state)
{
QObject * a = (QObject*)tolua_tousertype(state, , );
const char * signal = tolua_tostring(state, , );
QObject * b = (QObject*)tolua_tousertype(state, , );
const char * slot = tolua_tostring(state, , ); 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 ;
} static int tolua_delete_QWidget(lua_State* state)
{
qDebug() << "delete Start";
QWidget* widget = (QWidget* )tolua_tousertype(state, , );
if(NULL != widget)
{
qDebug() << "delete~";
widget->close();
delete widget;
}
return ;
} static int tolua_Show_QWidget(lua_State* state)
{
QWidget* widget = (QWidget* )tolua_tousertype(state, , ); if(widget != NULL)
{
widget->show();
}
return ;
} static int tolua_new_QPushButton(lua_State* state)
{
QPushButton* button = new QPushButton();
tolua_pushusertype(state, button, "QPushButton");
return ;
} static int tolua_delete_QPushButton(lua_State* state)
{
QPushButton* button = (QPushButton* )tolua_tousertype(state, , );
if(NULL != button)
{
button->close();
delete button;
}
return ;
} static int tolua_Show_QPushButton(lua_State* state)
{
QPushButton* button = (QPushButton* )tolua_tousertype(state, , ); if(button != NULL)
{
button->show();
}
return ;
} static int tolua_setText_QPushButton(lua_State* state)
{
QPushButton* button = (QPushButton* )tolua_tousertype(state, , );
const char * text = tolua_tostring(state, , ); if(button != NULL)
{
button->setText(QString::fromLocal8Bit(text));
}
return ;
} static int tolua_Resize_QWidget(lua_State* state)
{
QWidget* widget = (QWidget* )tolua_tousertype(state, , );
double a = tolua_tonumber(state, , );
double b = tolua_tonumber(state, , ); if(widget)
{
widget->resize((int)a, (int)b);
}
return ;
} static int QApplication_instance(lua_State* state)
{
tolua_pushusertype(state, QApplication::instance(), "QApplication");
return ;
} static int QApplication_quit(lua_State* state)
{
QApplication * app = (QApplication *)tolua_tousertype(state, , );
if(app)
app->quit();
return ;
} static int QApplication_delete(lua_State*)
{
return ;
} 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")

程序运行结果如下:

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

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

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

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

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

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