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


     

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

        QLua.h

    复制代码
     1 #ifndef QLUA_H
     2 #define QLUA_H
     3 
     4 // own
     5 #include "include/lua.hpp"
     6 
     7 // qt
     8 #include <QObject>
     9 #include <QFile>
    10 #include <QDebug>
    11 
    12 #include <QWidget>
    13 #include <QLineEdit>
    14 #include <QPushButton>
    15 #include <QMessageBox>
    16 
    17 class QLua : public QObject
    18 {
    19     Q_OBJECT
    20 public:
    21     QLua(QObject *parent = 0);
    22     ~QLua();
    23 
    24     // lua
    25     void init();
    26     void close();
    27 
    28     void pushFunction(QString funcName, lua_CFunction func);
    29 
    30     void beginModule(QString);
    31     void addType(QString, lua_CFunction deleteFunc);
    32     void moduleTypeFunction(QString, lua_CFunction);
    33     void endModule();
    34 
    35     void run(QString);
    36 signals:
    37 
    38 public slots:
    39 
    40 private:
    41     lua_State *luaState;
    42 
    43     bool isStartModule;
    44 };
    45 
    46 #endif // QLUA_H
    复制代码

        QLua.cpp

    复制代码
     1 #include "qlua.h"
     2 
     3 QLua::QLua(QObject *parent) :
     4     QObject(parent)
     5   , luaState(NULL)
     6   , isStartModule(false)
     7 {
     8     init();
     9 }
    10 
    11 QLua::~QLua()
    12 {
    13     close();
    14 }
    15 
    16 void QLua::init()
    17 {
    18     luaState = luaL_newstate();
    19     luaL_openlibs(luaState);
    20 }
    21 
    22 void QLua::close()
    23 {
    24     if(luaState != NULL)
    25     {
    26         lua_close(luaState);
    27         luaState = NULL;
    28     }
    29 }
    30 
    31 void QLua::pushFunction(QString funcName, lua_CFunction func)
    32 {
    33     if (funcName.isEmpty()) return;
    34     if (func == NULL)       return;
    35 
    36     lua_pushcfunction(luaState, func);
    37     lua_setglobal(luaState, funcName.toLocal8Bit().data());
    38 }
    39 
    40 void QLua::beginModule(QString name)
    41 {
    42     if(luaState == NULL) return;
    43 
    44     if (isStartModule == false)
    45     {
    46         tolua_open(luaState);
    47         tolua_module(luaState, NULL, 0);
    48         isStartModule = true;
    49     }
    50 
    51     const char *str = name.isEmpty()? NULL : name.toLocal8Bit().data();
    52     tolua_beginmodule(luaState, str);
    53 }
    54 
    55 void QLua::addType(QString name, lua_CFunction deleteFunc)
    56 {
    57     if (luaState == NULL) return;
    58     if (name.isEmpty())   return;
    59     if (deleteFunc == NULL) return;
    60 
    61     tolua_usertype(luaState, name.toLocal8Bit().data());
    62     const char *str = name.toLocal8Bit().data();
    63     tolua_cclass(luaState, str, str, "", deleteFunc);
    64     beginModule(name);
    65 }
    66 
    67 void QLua::moduleTypeFunction(QString name, lua_CFunction func)
    68 {
    69     if(luaState == NULL) return ;
    70     if (name.isEmpty())  return;
    71 
    72     const char *str = name.toLocal8Bit().data();
    73     tolua_function(luaState, str, func);
    74 }
    75 
    76 void QLua::endModule()
    77 {
    78     tolua_endmodule(luaState);
    79 }
    80 
    81 void QLua::run(QString str)
    82 {
    83     luaL_loadbuffer(luaState, str.toLocal8Bit().data(), str.length(), "line");
    84     lua_pcall(luaState, 0, 0, 0);
    85 }
    复制代码

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

    复制代码
     1 static int connect(lua_State* state)
     2 {
     3     QObject * a = (QObject*)tolua_tousertype(state, 1, 0);
     4     const char * signal = tolua_tostring(state, 2, 0);
     5     QObject * b = (QObject*)tolua_tousertype(state, 3, 0);
     6     const char * slot = tolua_tostring(state, 4, 0);
     7 
     8     QObject::connect(a, QString("2%0").arg(signal).toLocal8Bit().data(),
     9                      b, QString("1%0").arg(slot).toLocal8Bit().data());
    10 }
    复制代码

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

        程序运行结果如下:

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

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

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

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

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

  • 相关阅读:
    CVE-2020-14882&14883weblogic未授权命令执行漏洞复现
    不学点《近世代数》怎么学好现代密码学
    Android 7.0应用之间共享文件
    在.NET Core 中收集数据的几种方式
    浅析 TensorFlow Runtime 技术
    Linux — 进程管理
    【爬虫】爬取淮安信息职业学校(苏电院)的新闻网 python
    【爬虫】获取Github仓库提交纪录历史的脚本 python
    React入门学习笔记
    test
  • 原文地址:https://www.cnblogs.com/lvdongjie/p/4070872.html
Copyright © 2020-2023  润新知