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

话接上篇。通过前几篇博客,我们实现在Lua脚本中执行Qt类中函数的方法,以及在Lua脚本中连接Qt对象的信号与槽。

但是,我们也能发现,如果希望在Lua脚本中执行Qt类的函数,就必须绑定一个真正实现功能的函数。如QWidget::show(),需要写一个在栈中取出widget指针,widget调用show()函数的方式。如果希望在Lua中调用大量函数,就需要编写大量的C++实现函数。有没有什么省时省力的好方法呢?

上一篇中我们实现了在Lua脚本中连接信号与槽。我们只是传过去了两个QObject的对象,和两个字符串的函数名。我们并没有具体实现那个函数,但是槽函数顺利执行了。这给了笔者启发。如果我传过去一个函数名,理论上我可以找一个信号连接并激发它,也就达到了执行的目的。

OK,我们写这样一个函数:

static int exec(lua_State *state)
{
    QObject* obj = (QObject* )tolua_tousertype(state, 1, 0);
    const char * slot = tolua_tostring(state, 2, 0);

    if(obj != NULL)
    {
        RunSLOT run;
        QObject::connect(&run, SIGNAL(sendSignal()),
                obj, QString("1%0()").arg(slot).toLocal8Bit().data());
    }

    return 1;
}

取得QObject对象,以及字符串的槽函数名称。然后我们新建了一个RunSLOT对象,连接了run和obj对象。这样就能执行字符串代表的函数?

继续看RunSLOT类:

#ifndef RUNSLOT_H
#define RUNSLOT_H

#include <QObject>

class RunSLOT : public QObject
{
    Q_OBJECT
public:
    RunSLOT(QObject *parent = 0);
    ~RunSLOT();

signals:
    void sendSignal();
};

#endif // RUNSLOT_H

#include "runslot.h"

RunSLOT::RunSLOT(QObject *parent) :
    QObject(parent)
{
}

RunSLOT::~RunSLOT()
{
    emit sendSignal();
}

在析构是发出sendSignal信号,激发槽函数。而RunSLOT类对象run在遇到‘}’自动析构(C++局部变量原则),也就间接的执行了槽函数。

在绑定函数时将exec绑定到类里,然后写个测试脚本看看:

widget = QWidget:new()
widget:exec("show")

button = QPushButton:new()
button:exec("show")

connect(button, "clicked()", widget, "hide()")

成功显示一个窗体,一个按钮。

完整main.cpp如下:

// own
#include "include/lua.hpp"
#include "qlua.h"
#include "runslot.h"

// qt
#include <QWidget>
#include <QApplication>
#include <QFile>
#include <QDebug>

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());

    return 1;
}

static int exec(lua_State *state)
{
    QObject* obj = (QObject* )tolua_tousertype(state, 1, 0);
    const char * slot = tolua_tostring(state, 2, 0);

    if(obj != NULL)
    {
        RunSLOT run;
        QObject::connect(&run, SIGNAL(sendSignal()),
                obj, QString("1%0()").arg(slot).toLocal8Bit().data());
    }

    return 1;
}

static int QObject_delete(lua_State* state)
{
    qDebug() << "delete Start";
    QObject* obj = (QObject* )tolua_tousertype(state, 1, 0);
    if(NULL != obj)
    {
        qDebug() << "delete~";
        delete obj;
    }
    return 1;
}

static int QWidget_new(lua_State* state)
{
    QWidget* widget = new QWidget();
    tolua_pushusertype(state, widget, "QWidget");
    return 1;
}

static int QPushButton_new(lua_State* state)
{
    QPushButton* button = new QPushButton();
    tolua_pushusertype(state, button, "QPushButton");
    return 1;
}

static int QWidget_resize(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;
}

int main(int argc, char * argv[])
{
    Q_INIT_RESOURCE(resources);
    QApplication a(argc, argv);

    QLua lua;

    lua.beginModule("");

    lua.addType("QWidget", QObject_delete);
    lua.moduleTypeFunction("new", QWidget_new);
    lua.moduleTypeFunction("resize", QWidget_resize);
    lua.moduleTypeFunction("exec", exec);
    lua.endModule();

    lua.addType("QPushButton", QObject_delete);
    lua.moduleTypeFunction("new", QPushButton_new);
    lua.moduleTypeFunction("exec", exec);
    lua.endModule();

    lua.endModule();

    lua.pushFunction("connect", connect);

    // 读取资源文件
    QFile file("../../LuaTest/test.lua");
    file.open(QIODevice::ReadOnly | QIODevice::Text);

    QTextStream in(&file);
    in.setCodec("UTF-8");

    // 执行
    lua.run(in.readAll());

    return a.exec();
}

我们可以在将绑定exec函数写在QLua类里,添加类时就绑定这个函数。

当然,这个方法的局限性在于执行的函数无参数,而且必须是槽函数。如果想自由一个,可以在调用时写上参数,参数类型,C++这边判断并选择不同的信号连接方式,一劳永逸。

通过这个例子,我们可以发现,Qt本身就具备由字符串执行函数的能力,按照我的见解,这就是一种半动态。笔者会继续做下去,因为这个真的很有趣。

完整例程代码下载:http://pan.baidu.com/s/1sjFDiRb

转载注明出处:http://www.cnblogs.com/IT-BOY/

时间: 2024-11-05 20:33:06

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

ListView使用自定义适配器的情况下实现适配器的文本和图标控件点击事件执行Activity界面中的方法

ListView使用的是自定义适配器,列表项的布局文件中含有文本和图标,实现文本区域和图标区域的点击事件. 实现思路:在自定义适配器MyArrayAdapter 类型中自定义接口和接口方法,分别设置文本区域和图标区域的OnClickListener,然后在activity界面中MyArrayAdapter实例实现这个接口. 1.listitem布局文件 <?xml version="1.0" encoding="utf-8"?> <LinearLa

Android中Activity执行restart过程中涉及到的四种数据存储恢复的方法

我们知道,当Configuration Change发生的时候(比如横竖屏切换等),会导致Activity重启,即先destroy,然后会restart,一般情况下restart的时间比较短,为了保证一致的用户体验,我们应该在Activity重启前将一些数据存储下来,然后在restart的时候重新根据这些数据更新UI.当然你可能想将这些数据写到物理文件或数据库中,但是这样有缺点,因为IO操作时耗时操作,会影响restart的过程,甚至导致ANR程序无响应,本文将介绍几种将数据缓存在内存中以便re

Lua学习笔记--C调用Lua

Lua是一种嵌入式语言,可以很好的嵌入其他应用程序.lua为我们提供了一组灵活的C API,使C代码能够很好的与Lua进行交互.包括读写Lua全局变量,调用Lua函数,运行Lua代码,注册C函数反过来供Lua调用.简单的说,C能调用Lua,反过来Lua也能调用C.真的是灰常强大灵活的脚本!!现在,先来学习一下怎么用C调用Lua. 其实最简单的我们已经做过了,通过一个dofile,运行一个lua脚本文件. 一.栈 Lua与C的交互是通过一个虚拟栈进行的,这个栈对于Lua来说是严格的LIFO(后进先

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

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,但是因为使用

[Win32]一个调试器的实现(四)读取寄存器和内存

[Win32]一个调试器的实现(四)读取寄存器和内存 作者:Zplutor 出处:http://www.cnblogs.com/zplutor/ 本文版权归作者和博客园共有,欢迎转载.但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利. 在前几篇文章中,我实现的那个调试器只能被动接收调试事件并输出这些事件的信息.现在,我要将它修改成可以接收命令,并根据命令对被调试进程进行各种操作.首先从最基本的操作开始. 获取寄存器的值 每个线程都有一个上下文环境,它包

点击交互的四种处理

1.概述 游戏也好,程序也好.仅仅有能与用户交互才有意义. 手机上的交互大致能够分为两部分:点击和输入. 当中点击更为重要,差点儿是游戏中所有的交互.在Cocos2d-x 3.0中,更改了dispatch机制.同一时候增加了两种新的交互形式:listener 和touchEvent回调.加上先前版本号中的点击函数回调.与重写layer层的touch消息响应.构成了一个相对完整的交互模式.先上一张Demo的图: 2.四种点击 1.函数回调 函数回调是最简单的响应形式,一直以来被用于MenuItem

QT开发(五十四)———QML组件

QT开发(五十四)---QML组件 QML组件是由基本元素组合成的一个复杂的可重用的组合元素.QML 提供了多种方法来创建组件. 基于文件的组件将QML元素放置在一个单独的文件中,然后给文件一个名字,可以通过名字来使用组件.如果有一个文件名为Cell.qml,就可以在QML中使用Cell { - }形式.自定义组件的文件名的首字母必须大写. Cell.qml文件: import QtQuick 2.0   Item {     id: container     property alias c

在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