Russian Qt Forum

Qt => Qt Script, QtWebKit => Тема начата: Susenin от Октября 08, 2013, 23:45



Название: Qt Script. Сделать что-то вроде индексируемой переменной.
Отправлено: Susenin от Октября 08, 2013, 23:45
Всем привет.

Хочу, чтобы из скрипта были доступны свойства моего объекта вот так:
Код
Javascript
module.frequency(1) = 15;
var a = module.frequency(2);
 

В строке module.frequency(1) = 15; должно быть не присвоение 15 переменной, ссылку на которую вернет module.frequency(1),
а фактически вызов функции frequency c 2-мя параметрами: 1 - индекс, 2 - значение.
(В функции frequency я пишу число 15 по Modbus в регистр с индексом 1).

Почти то, что нужно описывается в документации http://qt-project.org/doc/qt-5.0/qtscript/qtscript-index.html#property-getters-and-setters (http://qt-project.org/doc/qt-5.0/qtscript/qtscript-index.html#property-getters-and-setters)

Цитировать
Property Getters and Setters
A script object property can be defined in terms of a getter/setter function, similar to how a Qt C++ property has read and write functions associated with it. This makes it possible for a script to use expressions like object.x instead of object.getX(); the getter/setter function for x will implicitly be invoked whenever the property is accessed. To scripts, the property looks and behaves just like a regular object property.
A single Qt Script function can act as both getter and setter for a property. When it is called as a getter, the argument count is 0. When it is called as a setter, the argument count is 1; the argument is the new value of the property. In the following example, we define a native combined getter/setter that transforms the value slightly:
QScriptValue getSet(QScriptContext *ctx, QScriptEngine *eng)
{
    QScriptValue obj = ctx->thisObject();
    QScriptValue data = obj.data();
    if (!data.isValid()) {
        data = eng->newObject();
        obj.setData(data);
    }
    QScriptValue result;
    if (ctx->argumentCount() == 1) {
        QString str = ctx->argument(0).toString();
        str.replace("Roberta", "Ken");
        result = str;
        data.setProperty("x", result);
    } else {
        result = data.property("x");
    }
    return result;
}

Недостаток 1: эти функции не могут быть методами класса. Соответственно this недоступен.
Недостаток 2: эти функции нужно прокидывать в глобальный объект явно, а хочется, чтобы они были доступны через объект
Код
C++ (Qt)
QScriptEngine eng;
QScriptValue obj = eng.newObject();
obj.setProperty("x", eng.newFunction(getSet), QScriptValue::PropertyGetter|QScriptValue::PropertySetter);
 

Подскажите, что делать? Можно, конечно, попить валерьянки, успокоиться ;D и оставить по 2-му варианту, но вдруг можно сделать красиво?

Что делал.
Вариант 1.
Есть объект со свойствами (так по-русски properties?):
Код
C++ (Qt)
class Module : public QObject
{
   Q_OBJECT
   Q_PROPERTY(quint32 frequency1     READ frequency1     WRITE setFrequency1)
   Q_PROPERTY(quint32 frequency2     READ frequency2     WRITE setFrequency2)
   ...
   Q_PROPERTY(quint32 frequency99   READ frequency99    WRITE setFrequency99)
 
private:
   ...
}
 

Код
Javascript
module.frequency1 = 15;
var a = module.frequency2;
 

Недостатки: некрасиво, много писанины, много возможностей ошибиться.

Вариант 2.
Вместо свойств делаю вызываемые методы:
Код
C++ (Qt)
class Module : public QObject
{
   Q_OBJECT
 
public:    
   Q_INVOKABLE quint32 frequency(quint8 index);
   Q_INVOKABLE void setFrequency(quint8 index, quint32 value);
}
 

Код
Javascript
module.setFrequency(1, 15);
var a = module.frequency(2);
 

Пока у меня реализован 2-й вариант.


Название: Re: Qt Script. Сделать что-то вроде индексируемой переменной.
Отправлено: lesav от Октября 09, 2013, 15:30
Сделать как в первом варианте со свойствами, и обращаться к ним используя магию JS (как к именованному массиву)
Код
Javascript
for(var i=1; i < 255; i++)
{
  module['frequency' + i] = 15
  var a = module['frequency' + i];
}
 


Название: Re: Qt Script. Сделать что-то вроде индексируемой переменной.
Отправлено: lesav от Октября 09, 2013, 15:33
В принципе этот подход можно попробовать и во втором варианте


Название: Re: Qt Script. Сделать что-то вроде индексируемой переменной.
Отправлено: Susenin от Октября 23, 2013, 11:32
Сделать как в первом варианте со свойствами, и обращаться к ним используя магию JS (как к именованному массиву)
Код
Javascript
for(var i=1; i < 255; i++)
{
  module['frequency' + i] = 15
  var a = module['frequency' + i];
}
 
Спасибо, магия JS помогла, так и сделал.