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"。内容如下:

#ifndef EXPOSE2LUA_H#define EXPOSE2LUA_H
extern "C"{ #include "lua.h" #include "lauxlib.h" #include "lualib.h"}#include "../libs/LuaBridge/LuaBridge.h"#include <stdio.h>#include <string>using namespace std;#define LuaDbgPrt#ifdef LuaDbgPrt #define luaLog printf#else #define luaLog(str)#endif#endif // EXPOSE2LUA_H



  • 类的配置

    在上述配置完成后,C++的类就可以方便地向Lua暴露接口了。举例如下:

#ifndef NIIF_H#define NIIF_H
#include "expose2lua.h"
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   }#endif // NIIF_H


这里稍展开说明一下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的主要内容,如果未能解决你的问题,请参考以下文章

qt creator源码全方面分析(2-0)

VS2008 集成Lua解释器

26.Qt Quick QML-RotationAnimationPathAnimationSmoothedAnimationBehaviorPauseAnimationSequential(代码片段

qt 环境下,Lua 与 QsciScintilla 库的使用

Lua - C++ 集成:从 C++ 调用表中的函数

在Pandoc lua过滤器中连接字符串片段