Win32下 Qt與Lua交互使用(四):在Lua腳本中自由執行Qt類中的函數

    話接上篇。經過前幾篇博客,咱們實如今Lua腳本中執行Qt類中函數的方法,以及在Lua腳本中鏈接Qt對象的信號與槽。ide

    可是,咱們也能發現,若是但願在Lua腳本中執行Qt類的函數,就必須綁定一個真正實現功能的函數。如QWidget::show(),須要寫一個在棧中取出widget指針,widget調用show()函數的方式。若是但願在Lua中調用大量函數,就須要編寫大量的C++實現函數。有沒有什麼省時省力的好方法呢?函數

    上一篇中咱們實現了在Lua腳本中鏈接信號與槽。咱們只是傳過去了兩個QObject的對象,和兩個字符串的函數名。咱們並無具體實現那個函數,可是槽函數順利執行了。這給了筆者啓發。若是我傳過去一個函數名,理論上我能夠找一個信號鏈接並激發它,也就達到了執行的目的。測試

    OK,咱們寫這樣一個函數:lua

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對象。這樣就能執行字符串表明的函數?spa

    繼續看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++局部變量原則),也就間接的執行了槽函數。code

    在綁定函數時將exec綁定到類裏,而後寫個測試腳本看看:對象

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

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

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

    成功顯示一個窗體,一個按鈕。blog

    完整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/

相關文章
相關標籤/搜索