Qt 集成 Lua
Posted sharelink
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Qt 集成 Lua相关的知识,希望对你有一定的参考价值。
Qt是好用的应用程序开发框架,界面可使用漂亮的QML。Qt基于C++,模块齐全,跨平台,容易上手。
Lua是开源轻量脚本语言,源码基于C,易用,非常灵活。
在编写应用程序时,总会有一些比较柔性的需求。最典型的场景,就是做测试软件,测试序列需要可编程,要求对硬件和数据操作有较高的柔性。这样的需求可能稍显复杂,简单地用配置文件,并不足以满足,但如果用C++实现,又必须每次都重新编译程序,稍显笨拙。Qt集成Lua,可以两者兼顾,用起来舒服,值得尝试。
已经有很多库可以实现C++和Lua的相互暴露。本着简单易用的原则,LuaBridge是首选。
LuaBridge是一个轻量级的库,主要用于Lua环境和C++环境之间数据、函数、类的映射。简而言之,就是用这个库,可以在Lua中调用C++定义的变量、函数或类,反之亦可。从它的名字,可以看出,它是一个“桥梁”。这个桥是双向的,但更多的应用场景关注如何在Lua中调用C++的接口,从而实现柔性化编程。所以接下来也只讲述这个方向的实现方法。
下载
https://github.com/vinniefalco/LuaBridge
源文件下载后放到合适的位置,比如工程文件夹源文件目录下。
配置工程文件
在Qt的项目文件.pro内部,添加这个库的路径,以及关于lua的配置。这些都 是常规操作。
#添加库文件夹的包含路径
INCLUDEPATH += libs\luaBridge
#添加lua的静态库文件
LIBS += $$PWD/libs/lua/libLua.a
#添加Lua的头文件
HEADERS += \
libs/lua/lauxlib.h \
libs/lua/lua.h \
libs/lua/lualib.h \
头文件处理
为了能在不同的类中,调用LuaBridge的接口函数,新建可复用的头文件,是一个便捷安全的做法。假设此头文件命名为"expose2lua.h"。内容如下:
extern "C"
{
}
using namespace std;
类的配置
在上述配置完成后,C++的类就可以方便地向Lua暴露接口了。举例如下:
class NIIF
{
public:
NIIF();
public:
std::string version;
void niLuaAout(std::string chnRes,qreal val){
...
}
void niLuaDout(std::string chnRes,int val){
...
}
int niLuaAin(lua_State* L){
luaL_checktype(L, 2, LUA_TSTRING);
std::string chnRes = lua_tostring(L,2);
QString chn=QString::fromStdString(chnRes);
luaLog("%s\n",chn.toStdString().data());
qreal dat = 0;
...
lua_Number ret = dat;
lua_settop(L, 0);
lua_pushnumber(L,ret);
return 1;
}
int niLuaDin(lua_State* L){
...
}
int niLuaCin(lua_State* L){
....
}
void luaOpen(lua_State* lua_state){
luabridge::getGlobalNamespace(lua_state)
.beginNamespace("niif") //注册C++类为lua命名空间
.beginClass<NIIF>("NIIF")
.addConstructor<void (*) (void)> ()//无参构造函数的注册
.addData("version", &NIIF::version)//注册静态变量到lua
.addFunction("niAout", &NIIF::niLuaAout)//注册方法到lua(addStaticFunction静态函数注册也类似)
.addFunction("niDout", &NIIF::niLuaDout)//注册方法到lua(addStaticFunction静态函数注册也类似)
.addCFunction("niAin",&NIIF::niLuaAin)//注册返回多个参数给lua的方法
.addCFunction("niDin",&NIIF::niLuaDin)
.addCFunction("niCin",&NIIF::niLuaCin)
.endClass()
.endNamespace();
luabridge::setGlobal(lua_state, this, "niobj");//注册对象到lua
}
这里稍展开说明一下LuaBridge的使用。首先要暴露的变量和函数须按LuaBridge格式要求定义好,然后,只需要一个函数luaOpen就可以将C++内容注册到Lua环境中。
对于变量,C++中按LuaBridge规则定义好,然后可以通过如下行,暴露到lua环境。
.addData("version", &NIIF::version)//注册静态变量到lua
//lua中使用此变量如下:
print(niobj.version)
对于函数,LuaBridge规定了2种函数,其一是普通函数(没有返回值),使用如下:
void niLuaAout(std::string chnRes,qreal val){
...
}
//注意其特征,首先是返回类型为void,其次是可直接带参数
.addFunction("niAout", &NIIF::niLuaAout)
//注册方法到lua(addStaticFunction静态函数注册也类似)
//lua中调用如下:
niobj:niAout('Dev1/Aout0',0.5)
另一种是有返回值的函数,使用如下:
int niLuaAin(lua_State* L){
luaL_checktype(L, 2, LUA_TSTRING);
std::string chnRes = lua_tostring(L,2);
QString chn=QString::fromStdString(chnRes);
qreal dat = 0;
...
lua_Number ret = dat;
lua_settop(L, 0);
lua_pushnumber(L,ret);
return 1;
}//通过lua_State这个句柄,将参数和返回值压入栈或从栈中弹出,实现交互
.addCFunction("niAin",&NIIF::niLuaAin)
//注册返回多个参数给lua的方法
//lua中调用如下:
ret= niobj:niAin('Dev1/Ain0')
print(ret)
以上是最基本的用法。但此时,我们还不能在Lua中调用niobj。因为C++和程序并没有提供一个Lua命令窗口或环境用于测试。接下来我们就实现在C++中实现这个Lua环境。
测试
为了测试,我们在C++窗口中,以文本文件方式,打开一个lua脚本,并逐行读入,用luaL_dostring逐行运行。逐行运行也可在定时器中进行,部分代码如下:
lua_State* lua_state = luaL_newstate();
luaL_openlibs(lua_state);//定义Lua环境
NIIF ni;
ni.luaOpen(lua_state);//暴露在这里实现
QFile *pFile = new QFile("test.lua");
pFile->open(QIODevice::ReadOnly);
if(pFile!=nullptr){
if(!pFile->atEnd()){
QByteArray line = pFile->readLine();
QString strc = GetCorrectUnicode(line);
//逐行运行
luaL_dostring(lua_sta, strc.toStdString().c_str());
}
}
Lua脚本测试文件如下:
print(niobj.version)
niobj:niAout("Dev1/Aout0",0.5)
ret= niobj:niAin("Dev1/Ain0")
print(ret)
以上就是Qt集成Lua的基本用法,用同样的原理,还可以实现很多复杂的功能,甚至可以用lua来实现界面的定制。
以上是关于Qt 集成 Lua的主要内容,如果未能解决你的问题,请参考以下文章
26.Qt Quick QML-RotationAnimationPathAnimationSmoothedAnimationBehaviorPauseAnimationSequential(代码片段