zoukankan      html  css  js  c++  java
  • QT绑定Lua脚本,相互调用

    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] = '';
     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 }
     76 int QtWidgetBridgeLua::qtCallLuaAdd(int x, int y)
     77 {
     78     int sum;
     79     lua_getglobal(L, "add");
     80     lua_pushnumber(L, x);
     81     lua_pushnumber(L, y);
     82 
     83     lua_call(L, 2, 1); //2个参数, 1个返回值
     84     sum = (int)lua_tonumber(L, -1); //获取结果
     85     lua_pop(L, 1); //清除返回值,弹出栈
     86     return sum;
     87 }
     88 int QtWidgetBridgeLua::qtCallLuaStrlen(std::string str)
     89 {
     90     int len;
     91     lua_getglobal(L, "strlen");
     92     lua_pushstring(L, str.c_str());
     93     lua_call(L, 1, 1);
     94     len = (int)lua_tonumber(L, -1);
     95     lua_pop(L, 1);
     96     return len;
     97 }
     98 std::string QtWidgetBridgeLua::qtCallLuaRandomStr(int cnt)
     99 {
    100     lua_getglobal(L, "randomStr");
    101     lua_pushnumber(L, cnt);
    102     lua_call(L, 1, 1);
    103     const char* str = lua_tostring(L, -1);
    104     lua_pop(L, 1);
    105     return std::string(str);
    106 }
    107 void QtWidgetBridgeLua::qtCallLuaPrint()
    108 {
    109     lua_getglobal(L, "printInfo");
    110     lua_call(L, 0, 0);
    111     return ;
    112 }

      mainwindow.ui

      (略)

      A.lua

     1 function add(x,y)
     2     return x - y
     3 end
     4 function strlen(str)
     5     return #str
     6 end
     7 function printInfo(str)
     8     print("printInfo")
     9 end
    10 function randomStr(len)
    11     local rankStr = ""
    12     local randNum = 0
    13     math.randomseed(os.time())
    14     for i=1,len do
    15       if math.random(1,3)==1 then
    16         randNum=string.char(math.random(0,25)+65)   --生成大写字母 random(0,25)生成0=< <=25的整数
    17       elseif math.random(1,3)==2 then
    18         randNum=string.char(math.random(0,25)+97)   --生成小写字母
    19       else
    20         randNum=math.random(0,9)                   --生成0=< and <=9的随机数字
    21       end
    22       rankStr=rankStr..randNum
    23     end
    24     return rankStr
    25 end

      B.lua

     1 print("lua call调用 Qt Class")
     2 local utils = QtUtils();
     3 utils.member="aaaa"
     4 print(utils.member)
     5 local val = utils:luaCallQtAdd(10, 20)
     6 print("lua call qt add: " .. val)
     7 local len = utils:luaCallQtStrlen("Hello World ~~~~~~~")
     8 print("lua call qt strlen: " .. len)
     9 local str = utils:luaCallQtRandomStr(16);
    10 print("lua call qt random: " .. str)
    11 utils.member = "Member ****==> "
    12 utils.value = 1024
    13 utils:luaCallQtPrint()

    5. 运行效果

    参考资料:
      https://www.runoob.com/lua/lua-tables.html
      https://www.cnblogs.com/Hichy/p/7060226.html
      http://www.cppblog.com/sunicdavy/archive/2013/12/07/204648.html
      https://blog.csdn.net/qq_31073871/article/details/81285791
      https://blog.csdn.net/FL63Zv9Zou86950w/article/details/78402879
      http://www.lua.org/download.html
      https://github.com/vinniefalco/LuaBridge
      http://vinniefalco.github.io/LuaBridge/Manual.html#s2.1

    本文地址: https://www.cnblogs.com/wunaozai/p/14087370.html

  • 相关阅读:
    IKAnalyzer
    stanford corenlp的TokensRegex
    Linux网络编程-tcp缓存设置
    Java NIO(2):缓冲区基础
    Java NIO(1):迟迟登场的NIO
    git的笔记和使用中的一些技巧的总结
    vagrant 系列 博客
    flutter创建swift kotlin项目
    react eject 命令失败
    react native react-native-vector-icons/Ionicons 出现 Unrecognized font family的错误
  • 原文地址:https://www.cnblogs.com/wunaozai/p/14087370.html
Copyright © 2011-2022 走看看