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/

时间: 2024-08-26 03:23:14

Win32下 Qt与Lua交互使用(三):在Lua脚本中connect Qt 对象的相关文章

Win32下 Qt与Lua交互使用(二):在Lua脚本中使用Qt类

话接上篇.成功配置好Qt+Lua+toLua后,我们可以实现在Lua脚本中使用各个Qt的类.直接看代码吧. #include "include/lua.hpp" #include <QWidget> #include <QApplication> #include <QFile> #include <QDebug> static int tolua_new_QWidget(lua_State* pState) { QWidget* wid

Lua初学者(三)--Lua 嵌入宿主语言(C++/C)

继续上节内容,在C中使用Lua,这个网上资源也比较多了,不过我这里也提下哈,毕竟自己过一遍还是很有好处的. 环境:Lua5.1,vs2013中文版 ----------------------------------------------------一.C++中配置 lua---------------------------------------- 1.下载lua源码么:http://www.lua.org/download.html 就OK了 2.打开VS2013,新建工程: 新建-->

Win32下 Qt与Lua交互使用(四):在Lua脚本中自由执行Qt类中的函数

话接上篇.通过前几篇博客,我们实现在Lua脚本中执行Qt类中函数的方法,以及在Lua脚本中连接Qt对象的信号与槽. 但是,我们也能发现,如果希望在Lua脚本中执行Qt类的函数,就必须绑定一个真正实现功能的函数.如QWidget::show(),需要写一个在栈中取出widget指针,widget调用show()函数的方式.如果希望在Lua中调用大量函数,就需要编写大量的C++实现函数.有没有什么省时省力的好方法呢? 上一篇中我们实现了在Lua脚本中连接信号与槽.我们只是传过去了两个QObject的

Win32下 Qt与Lua交互使用:配置Qt下Lua运行环境

Lua与C++之间可以实现非常强的交互性.Lua中可以使用C++中的函数,C++中也可以使用Lua中的函数.由此可以引发出很多奇思妙想了. 简单来说,Lua动态的特性补充了C++的功能.当然,也看你具体怎么用. 笔者经常使用Qt,故准备将Qt和Lua结合在一起.想象一下在Lua脚本中调用如下代码: w = QWidget:new() w:show() 然后弹出一QWidget的窗口,是多么感人的一件事情呀. 好,下面开始配置环境吧. 1. 下载Lua 5.1.目前的最新版本是5.2,但是因为使用

Lua脚本和C++交互(三)

前两篇文章中介绍了C++调用lua.lua栈操作的一些相关知识. 下面说一下Lua的工具.我们下一步要用到其中的一个帮助我们的开发,其实,Lua里面有很多简化开发的工具,你可以去www.sourceforge.net去找一下.它们能够帮助你简化C++对象与Lua对象互转之间的代码.这里说几个有名的,当然可能不全. (lua tinker)如果你的系统在windows下,而且不考虑移植,那么我强烈推荐你去下载一个叫做lua tinker的小工具,整个工具非常简单,一个.h和一个.cpp.直接就可以

在C++使用LUA交互,LUA实现闭包,C++/LUA相互闭包

LUA可谓是配置文件神器,具体功能用过才知道,接近两年没用了抽了俩小时熟悉了下基本的用法. 包括C/LUA堆栈操作 函数相互调用 以及LUA的闭包 C++和LUA相互闭包 想要灵活使用LUA必须先要学习 LUA和C的堆栈交互模型 类似于汇编函数调用方式了 很有意思. 要学习LUA首先要理解LUA和C/C++交互的堆栈lua_State  这里引用网友的一篇文章很详细 http://wind-catalpa.blog.163.com/blog/static/11475354320131191031

[Win32]一个调试器的实现(三)异常

[Win32]一个调试器的实现(三)异常 作者:Zplutor 出处:http://www.cnblogs.com/zplutor/ 本文版权归作者和博客园共有,欢迎转载.但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利. 这回接着处理上一篇文章留下的问题:如何处理EXCEPTION_DEBUG_EVENT这类调试事件.这类调试事件是调试器与被调试进程进行交互的最主要手段,在后面的文章中你会看到调试器如何使用它完成断点.单步执行等操作.所以,关于这类调

Android中WebView的JavaScript代码和本地代码交互的三种方式

一.Android中WebView的漏洞分析 最近在开发过程中遇到一个问题,就是WebView使用的时候,还是需要解决之前系统(4.2之前)导致的一个漏洞,虽然现在这个系统版本用户很少了,但是也不能忽视,关于这个漏洞,这里就不多做解释了,可能有的同学早就了解了,本来想写一篇文章详细介绍一下,但是网上的知识太多了,而且都很详细,就没弄了,这里大致简单明了的说几句: 第一.漏洞产生的原因 这个漏洞导致的原因主要是因为Android中WebView中的JS访问本地方法的方式存在缺陷,我们做过交互的都知

Qt那点事儿(三) 论父对象与子对象的关系

第三回 父与子 70后的道友都应该看过这么一部片子叫做<<父子情深>>.讲述的是一个小男孩患了绝症,父亲为了满足他的愿望,让已关门的游乐园为他们父子俩重新开放.在游乐园尽情地玩耍后,最后小孩子在父亲的怀中安详地闭上了眼睛.缓缓转动的摩天轮,配着淡淡忧伤的曲调,这一刻哥泪流满面.谁说世上只有妈妈好,父爱也顶半边天.此时台下的众多男道友热泪盈眶,不约而同地起立鼓掌.史上最大的冤屈,终于得以昭雪. 但是人世间这种真挚的父爱也存在于Qt中吗? 对此,从小缺乏父爱的张无忌小友给出了自己的答案