• 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/

  • 相关阅读:
    java——异常——自定义异常类——练习
    java——异常——异常注意事项:子父类异常
    java——异常——异常注意事项:finally有return语句——如果finally有return语句,永远返回finally中的结果,避免该情况.
    java——异常——throws关键字:异常处理的第一种方式,交给别人处理
    java——异常——try...catch:异常处理的第二种方式,自己处理异常——Throwable类中定义了3个异常处理的方法——String getMessage() 返回此 throwable 的简短描述——String toString() 返回此 throwable 的详细消息字符串——void printStackTrace() JVM打印异常对象,默认此方法,打印的异常信息是最全面的
    java——多线程——并发与并行的了解以及区别
    java——异常——try...catch:异常处理的第二种方式,自己处理异常
    java——异常——自定义异常类
    java——异常——异常注意事项:多异常捕获处理
    java——异常——finally代码块
  • 原文地址:https://www.cnblogs.com/lvdongjie/p/4070876.html
Copyright © 2020-2023  润新知