• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

QT绑定Lua脚本,相互调用

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

0. 前言
  最近有个需求,就是需要在QT(C++)中移植lua脚本。达到可以动态更新软件功能。lua是一门脚本语言。常用于各类编程语言,作为脚本。特别是游戏行业,据说很多用lua脚本来写业务逻辑。本次分为两种调用,一种是QT调用Lua,这种比较简单。利用Lua源码编译后,直接就可以使用。另外一种是Lua调用QT里面的函数,这种就比较麻烦,这里采用第三方库LuaBridge。


1. 安装,编译
  到lua官网下载lua源代码,我这里使用5.3版本。然后在GitHub上,下载LuaBridge源码(下载路径在本文最后面的参考资料里面)。然后把源码加到QT工程目录下。目录结构如下:

  配置QT工程文件 LuaDemo.pro 两个注意点,注意lua版本间的差异。还有就是SOURCES += 加入C文件时, lua.c luac.c 这两个文件不要加入到编译文件中。下面这个pro工程文件,仅供参考

 1 QT       += core gui
 2 
 3 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
 4 
 5 CONFIG += c++11
 6 
 7 # The following define makes your compiler emit warnings if you use
 8 # any Qt feature that has been marked deprecated (the exact warnings
 9 # depend on your compiler). Please consult the documentation of the
10 # deprecated API in order to know how to port your code away from it.
11 DEFINES += QT_DEPRECATED_WARNINGS
12 
13 # You can also make your code fail to compile if it uses deprecated APIs.
14 # In order to do so, uncomment the following line.
15 # You can also select to disable deprecated APIs only up to a certain version of Qt.
16 #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
17 
18 SOURCES += \
19         lua-5.3.5/src/lapi.c    \
20         lua-5.3.5/src/lauxlib.c \
21         lua-5.3.5/src/lbaselib.c\
22         lua-5.3.5/src/lbitlib.c \
23         lua-5.3.5/src/lcode.c   \
24         lua-5.3.5/src/lcorolib.c\
25         lua-5.3.5/src/lctype.c  \
26         lua-5.3.5/src/ldblib.c  \
27         lua-5.3.5/src/ldebug.c  \
28         lua-5.3.5/src/ldo.c     \
29         lua-5.3.5/src/ldump.c   \
30         lua-5.3.5/src/lfunc.c   \
31         lua-5.3.5/src/lgc.c     \
32         lua-5.3.5/src/linit.c   \
33         lua-5.3.5/src/liolib.c  \
34         lua-5.3.5/src/llex.c    \
35         lua-5.3.5/src/lmathlib.c\
36         lua-5.3.5/src/lmem.c    \
37         lua-5.3.5/src/loadlib.c    \
38         lua-5.3.5/src/lobject.c    \
39         lua-5.3.5/src/lopcodes.c\
40         lua-5.3.5/src/loslib.c  \
41         lua-5.3.5/src/lparser.c \
42         lua-5.3.5/src/lstate.c  \
43         lua-5.3.5/src/lstring.c \
44         lua-5.3.5/src/lstrlib.c \
45         lua-5.3.5/src/ltable.c  \
46         lua-5.3.5/src/ltablib.c \
47         lua-5.3.5/src/ltm.c     \
48         lua-5.3.5/src/lundump.c    \
49         lua-5.3.5/src/lutf8lib.c\
50         lua-5.3.5/src/lvm.c     \
51         lua-5.3.5/src/lzio.c    \
52         main.cpp \
53         mainwindow.cpp \
54         qtwidgetbridgelua.cpp
55 
56 
57 
58 HEADERS += \
59     common.h \
60     mainwindow.h \
61     qtwidgetbridgelua.h
62 
63 #INCLUDEPATH += lua-5.2.0/src
64 INCLUDEPATH += lua-5.3.5/src
65 
66 
67 FORMS += \
68     mainwindow.ui
69 
70 # Default rules for deployment.
71 qnx: target.path = /tmp/$${TARGET}/bin
72 else: unix:!android: target.path = /opt/$${TARGET}/bin
73 !isEmpty(target.path): INSTALLS += target

  头文件引用 common.h 这里引用lua.hpp, 还有LuaBridge.h 即可。

 1 #ifndef COMMON_H
 2 #define COMMON_H
 3 
 4 #include "lua.hpp"
 5 #include "LuaBridge/LuaBridge.h"
 6 
 7 #include <QString>
 8 #include <QRandomGenerator>
 9 #include <QDebug>
10 
11 
12 #endif // COMMON_H

  这样就把lua和LuaBridge依赖关系搞定了。接下来就是写逻辑代码了。


2. QT调用Lua

  QT调用Lua,相对比较简单。

 1 lua_State * LUA;
 2 int luaAdd(int x, int y)
 3 {
 4     int sum;
 5     lua_getglobal(LUA, "add");
 6     lua_pushnumber(LUA, x);
 7     lua_pushnumber(LUA, y);
 8     lua_call(LUA, 2, 1); //2个参数, 1个返回值
 9     sum = (int)lua_tonumber(LUA, -1); //获取结果
10     lua_pop(LUA, 1); //清楚返回值,弹出栈
11     return sum;
12 }
13 
14 int main(int argc, char *argv[])
15 {
16     LUA = luaL_newstate(); //新建lua解释器
17     luaL_openlibs(LUA); //载入lua基础库
18     //执行lua脚本
19     //luaL_loadfile(LUA, "add.lua"); //载入lua脚本
20     luaL_dofile(LUA, "add.lua");
21     int sum = luaAdd(10, 20);
22     qDebug() << "sum: " << sum;
23     lua_close(LUA);
24     return 0;
25 }

 

3. Lua调用QT

  定义几个Class

 1 class A
 2 {
 3 public:
 4     A() {  }
 5     virtual void foo( int a ) {
 6         qDebug() << "foo base: " << a << ":" << Member.c_str();
 7     }
 8     std::string Member;
 9 };
10 
11 class B : public A
12 {
13 public:
14     virtual void foo( int a ) {
15         qDebug() << "foo inherited: " << a << ":" << Member.c_str();
16     }
17 };
18 void foo(int a) {
19     qDebug() << "foo: " << a;
20 }
 1 class A; class B;
 2 lua_State * LUA;
 3 int main(int argc, char *argv[])
 4 {
 5     qDebug() << "aab";
 6     lua_State* L = luaL_newstate();
 7     //加载Lua基本库
 8     luaL_openlibs(L);
 9     luabridge::getGlobalNamespace(L)
10             .beginClass<A>("Sobj")
11                 .addConstructor<void (*) (void)> ()
12                 .addFunction("foo", &A::foo)
13                 .addData("Member",&A::Member)
14             .endClass()
15             .deriveClass<B, A>("SSec")
16                 .addFunction("foo",&B::foo )
17             .endClass();
18     luabridge::getGlobalNamespace(L).addFunction("foo", foo );
19 
20     B ins;
21     ins.Member = "data";
22     luabridge::setGlobal(L, ins, "ins");
23     ins.foo(3);
24 
25     luaL_dofile(L, "qt.lua");
26     return 0;
27 }

  Lua脚本

1 print('start')
2 local a = Sobj()
3 a.Member='World'
4 a:foo(2)
5 ins.Member='Hello'
6 ins:foo(3)
7 foo(1)
8 print('end')

 

 

4. 代码预览

  common.h

 1 #ifndef COMMON_H
 2 #define COMMON_H
 3 
 4 #include "lua.hpp"
 5 #include "LuaBridge/LuaBridge.h"
 6 
 7 #include <QString>
 8 #include <QRandomGenerator>
 9 #include <QDebug>
10 
11 
12 #endif // COMMON_H

  mainwindow.h

 1 #ifndef MAINWINDOW_H
 2 #define MAINWINDOW_H
 3 
 4 #include "qtwidgetbridgelua.h"
 5 #include <QMainWindow>
 6 
 7 QT_BEGIN_NAMESPACE
 8 namespace Ui { class MainWindow; }
 9 QT_END_NAMESPACE
10 
11 class MainWindow : public QMainWindow
12 {
13     Q_OBJECT
14 
15 public:
16     MainWindow(QWidget *parent = nullptr);
17     ~MainWindow();
18 
19 private slots:
20     void on_btnQtCallLua_clicked();
21     void on_btnLuaCallQt_clicked();
22 
23 private:
24     Ui::MainWindow *ui;
25     QtWidgetBridgeLua lua;
26 };
27 #endif // MAINWINDOW_H

  qtwidgetbridgelua.h

 1 #ifndef QTWIDGETBRIDGELUA_H
 2 #define QTWIDGETBRIDGELUA_H
 3 
 4 #include "common.h"
 5 
 6 class QtWidgetBridgeLua
 7 {
 8 public:
 9     QtWidgetBridgeLua();
10     ~QtWidgetBridgeLua();
11 
12     //加载Lua调Qt的脚本
13     void luaCallQtLoadCode(QString code);
14     //注册所有函数
15     void registerFunction();
16     //加法
17     int luaCallQtAdd(int x, int y);
18     //计算字符长度
19     int luaCallQtStrlen(std::string str);
20     //产生随机数
21     std::string luaCallQtRandomStr(int cnt);
22     //打印变量
23     void luaCallQtPrint();
24 
25     //加载Qt调用Lua的脚本
26     void qtCallLuaLoadCode(QString code);
27     //加法
28     int qtCallLuaAdd(int x, int y);
29     //计算字符长度
30     int qtCallLuaStrlen(std::string str);
31     //产生随机数
32     std::string qtCallLuaRandomStr(int cnt);
33     //打印变量
34     void qtCallLuaPrint();
35 
36 public:
37     std::string member;
38     int value;
39 
40 private:
41     lua_State * L;
42 };
43 
44 #endif // QTWIDGETBRIDGELUA_H

  main.cpp

 1 #include "mainwindow.h"
 2 #include "qtwidgetbridgelua.h"
 3 
 4 #include <QApplication>
 5 #include <QDebug>
 6 
 7 //#include "lua.hpp"
 8 //#include "LuaBridge/LuaBridge.h"
 9 
10 int main(int argc, char *argv[])
11 {
12     QApplication a(argc, argv);
13     MainWindow w;
14     w.show();
15     return a.exec();
16 }

  mainwindow.cpp

 1 #include "mainwindow.h"
 2 #include "ui_mainwindow.h"
 3 
 4 MainWindow::MainWindow(QWidget *parent)
 5     : QMainWindow(parent)
 6     , ui(new Ui::MainWindow)
 7 {
 8     ui->setupUi(this);
 9 
10 }
11 
12 MainWindow::~MainWindow()
13 {
14     delete ui;
15 }
16 
17 void MainWindow::on_btnQtCallLua_clicked()
18 {
19     QString txt = ui->txtQtCallLua->toPlainText();
20     lua.qtCallLuaLoadCode(txt);
21     qDebug() << "qt call lua:";
22     //调用加法计算
23     int sum = lua.qtCallLuaAdd(20, 30);
24     qDebug() << "add :" << sum;
25     //调用计算字符串长度
26     int len = lua.qtCallLuaStrlen("Hello World!!");
27     qDebug() << "strlen: " << len;
28     //调用随机数
29     std::string randstr = lua.qtCallLuaRandomStr(12);
30     qDebug() << "randstr: " << randstr.c_str();
31     //调用打印
32     lua.qtCallLuaPrint();
33 }
34 
35 void MainWindow::on_btnLuaCallQt_clicked()
36 {
37     QString txt = ui->txtLuaCallQt->toPlainText();
38     lua.luaCallQtLoadCode(txt);
39 }

  qtwidgetbridgelua.cpp

  1 #include "qtwidgetbridgelua.h"
  2 
  3 QtWidgetBridgeLua::QtWidgetBridgeLua()
  4 {
  5     L = luaL_newstate(); //新建lua解析器
  6     luaL_openlibs(L); //载入lua基础库
  7 }
  8 QtWidgetBridgeLua::~QtWidgetBridgeLua()
  9 {
 10     lua_close(L); //释放lua解析器
 11 }
 12 
 13 /****************Lua调用Qt函数*******************/
 14 void QtWidgetBridgeLua::luaCallQtLoadCode(QString code)
 15 {
 16     //每次都重新创建lua解析器
 17     lua_close(L);
 18     L = luaL_newstate();
 19     luaL_openlibs(L);
 20     //注册所有函数
 21     registerFunction();
 22     luaL_dostring(L, code.toStdString().c_str()); //加载脚本
 23     //luaL_dofile(L, "sample.lua"); //文件方式加载脚本
 24 }
 25 void QtWidgetBridgeLua::registerFunction()
 26 {
 27     luabridge::getGlobalNamespace(L)
 28             .beginClass<QtWidgetBridgeLua>("QtUtils")
 29                 .addConstructor<void (*) (void)>()
 30                 .addFunction("luaCallQtAdd", &QtWidgetBridgeLua::luaCallQtAdd)
 31                 .addFunction("luaCallQtStrlen", &QtWidgetBridgeLua::luaCallQtStrlen)
 32                 .addFunction("luaCallQtRandomStr", &QtWidgetBridgeLua::luaCallQtRandomStr)
 33                 .addFunction("luaCallQtPrint", &QtWidgetBridgeLua::luaCallQtPrint)
 34                 .addData("member", &QtWidgetBridgeLua::member)
 35                 .addData("value", &QtWidgetBridgeLua::value)
 36             .endClass();
 37 }
 38 int QtWidgetBridgeLua::luaCallQtAdd(int x, int y)
 39 {
 40     return x + y;
 41 }
 42 int QtWidgetBridgeLua::luaCallQtStrlen(std::string str)
 43 {
 44     return str.length();
 45 }
 46 std::string QtWidgetBridgeLua::luaCallQtRandomStr(int cnt)
 47 {
 48     const char ch[] = "0123456789abcdefABCDEF";
 49     int start = 0;
 50     int end = sizeof(ch) - 1;
 51     char *str = new char[cnt + 1];
 52     for(int i=0; i<cnt; i++)
 53     {
 54         int val = QRandomGenerator::global()->bounded(start, end);
 55         str[i] = ch[val];
 56     }
 57     str[cnt] = '\0';
 58     return std::string(str);
 59 }
 60 void QtWidgetBridgeLua::luaCallQtPrint()
 61 {
 62     qDebug() << this->member.c_str() << " : " << this->value;
 63 }
 64 
 65 /****************Qt调用Lua函数*******************/
 66 void QtWidgetBridgeLua::qtCallLuaLoadCode(QString code)
 67 {
 68     //每次都重新创建lua解析器
 69     lua_close(L);
 70     L = luaL_newstate();
 71     luaL_openlibs(L);
 72 
 73     luaL_dostring(L, code.toStdString().c_str()); //加载脚本
 74     //luaL_dofile(L, "sample.lua"); //文件方式加载脚本
 75 } 

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
LuaAPI小记2(lua值,栈解释)发布时间:2022-07-22
下一篇:
Lua初学发布时间:2022-07-22
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap