Russian Qt Forum
Ноябрь 25, 2024, 07:25 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Синхронизировать property  (Прочитано 6443 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Ноябрь 07, 2013, 19:00 »

Добрый день

Занимаюсь прикруткой скриптов, и все вроде удачно "легло", но вылазит противная мелочевка (не вписывающаяся в общую схему  Плачущий). Мои объекты мапируются в пытон переменные используя проперди, напр
Код:
py> obj.Geometry.Position.x = 100
Объект obj имеет property Geometry которая порождена от QObject и имеет property Position (типа QVector3D). Все работает. Однако пользователь может переключить управление объектом, в результате вместо одной проперди Position будут 3 другие, в пытоне выглядит так
Код:
py>obj.Geometry.Yaw = 100      # так называется x ;-)
py>obj.Geometry.Pitch = 0        # y
py>obj.Geometry.Roll = 0          # z
Тоже работает. Но юзверю неинтересно все время набирать "Geometry" и редактировать скрипты при смене режима. Он хочет писать так
Код:
py> obj.Position.x = 100
Ну добавил property Position (на том же уровне что и Geometry), но что делать в такой ситуации
Код:
py> obj.Position.x = 100
py> test = obj.Geometry.Yaw
То есть 2 проперди должны шарить одни данные. При этом пропердь Yaw создается только когда происходит обращение к проперди Geometry

Спасибо
Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 872


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #1 : Ноябрь 12, 2013, 10:15 »

Но юзверю неинтересно все время набирать "Geometry" и редактировать скрипты при смене режима. Он хочет писать так
Код:
py> obj.Position.x = 100
Ваши пользователи желают странного Улыбающийся
Но можно сделать с использованием врапперов:
Код:
// прикладные классы
class Position
{
public:
    int x;
    int y;
    int z;
};

class Geometry
{
public:
    Position position;
};

class Queer
{
public:
    Geometry geometry;
};
Код:
// врапперы прикладных классов
class PositionWrapper : public QObject {
    Q_OBJECT

public slots:
    // конструктор и деструктор
    Position* new_Position() { return new Position(); }
    void delete_Position(Position* o) { delete o; }

    // эмуляторы свойств
    int py_get_x(Position* o) { return o->x; }
    void    py_set_x(Position* o, int value) { o->x = value; }
    int py_get_y(Position* o) { return o->y; }
    void    py_set_y(Position* o, int value) { o->y = value; }
    int py_get_z(Position* o) { return o->z; }
    void    py_set_z(Position* o, int value) { o->z = value; }
};

class GeometryWrapper : public QObject {
    Q_OBJECT

public slots:
    // конструктор и деструктор
    Geometry* new_Geometry() { return new Geometry(); }
    void delete_Geometry(Geometry* o) { delete o; }

    // эмуляторы свойств
    int py_get_yaw(Geometry* o) { return o->position.x; }
    void    py_set_yaw(Geometry* o, int value) { o->position.x = value; }
    int py_get_pitch(Geometry* o) { return o->position.y; }
    void    py_set_pitch(Geometry* o, int value) { o->position.y = value; }
    int py_get_roll(Geometry* o) { return o->position.z; }
    void    py_set_roll(Geometry* o, int value) { o->position.z = value; }

    Position* py_get_position(Geometry* o) { return &o->position; }
    void    py_set_position(Geometry* o, Position value) { o->position = value; }
};

class QueerWrapper : public QObject {
    Q_OBJECT

public slots:
    // конструктор и деструктор
    Queer* new_Queer() { return new Queer(); }
    void delete_Queer(Queer* o) { delete o; }

    // эмуляторы свойств
    Geometry* py_get_geometry(Queer* o) { return &o->geometry; }
    void    py_set_geometry(Queer* o, Geometry value) { o->geometry = value; }

    Position* py_get_position(Queer* o) { return &o->geometry.position; }
    void    py_set_position(Queer* o, Position value) { o->geometry.position = value; }
};
Код:
    // регистрация прикладных классов
    PythonQt::self()->registerCPPClass("Position", "","QtCore", PythonQtCreateObject<PositionWrapper>);
    PythonQt::self()->registerCPPClass("Geometry", "","QtCore", PythonQtCreateObject<GeometryWrapper>);
    PythonQt::self()->registerCPPClass("Queer", "","QtCore", PythonQtCreateObject<QueerWrapper>);
Теперь можно и так, и так:
Код:
py>obj = Queer()
py>obj.geometry.position.x = 100
py>print obj.geometry.yaw
100

py>obj.geometry.pitch = 200
py>print obj.geometry.position.y
200
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Ноябрь 13, 2013, 11:38 »

Код:
class GeometryWrapper : public QObject {
    Q_OBJECT

public slots:
...
    void    py_set_yaw(Geometry* o, int value) { o->position.x = value; }
А что если данный экземпляр Geomеtry не имеет атрибута yaw? (а др экземпляр имеет). Надо выбрасывать exception, но как выскочить на данные приложения?

Та же проблема приходит с др стороны.
Код:
class PositionWrapper : public QObject {
    Q_OBJECT

public slots:
    void    py_set_x(Position* o, int value) { o->x = value; }
Да, если просто мапить переменные - все прекрасно, после выполнения скрипта они заполнены данными. Но мне нужно по присвоению атрибута немедленно произвести действия. Пример: скрипт изменил позицию объекта "Сфера" который в приложении parent других объектов - значит все они должны быть тоже передвинуты. Если какие-то из них тоже участвуют в скрипте - их позиции должны быть изменены и там. Напрашивается так
Код:
void py_set_x(Position* o, int value) 
{
  o->x = value;
  o->p->DoModifyX();   // p - указатель на данные приложения
}
Но ведь экземпляр Position может быть просто пытон-переменной, которая к приложению не имеет отношения, напр
Код:
py> test = Position()
И что тогда  Непонимающий
« Последнее редактирование: Ноябрь 13, 2013, 11:40 от Igors » Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 872


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #3 : Ноябрь 13, 2013, 18:19 »

Напрашивается так
Код:
void py_set_x(Position* o, int value) 
{
  o->x = value;
  o->p->DoModifyX();   // p - указатель на данные приложения
}
Но ведь экземпляр Position может быть просто пытон-переменной, которая к приложению не имеет отношения, напр
Код:
py> test = Position()
И что тогда  Непонимающий
Как вариант, "p" сделать статическим членом Position, тогда все экземпляры Position будут иметь к нему доступ. Можно вообще сделать отдельный класс, собрать в нем статические данные и сделать его ответственным за обмен между скриптами и приложением. Будет у вас некий шлюз. Могу даже подарить название класса - ScriptGateway Подмигивающий
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Ноябрь 14, 2013, 01:22 »

Как вариант, "p" сделать статическим членом Position, тогда все экземпляры Position будут иметь к нему доступ. Можно вообще сделать отдельный класс, собрать в нем статические данные и сделать его ответственным за обмен между скриптами и приложением. Будет у вас некий шлюз. Могу даже подарить название класса - ScriptGateway Подмигивающий
Так а что мне даст статический член?
Код:
py> test = Position()    # это просто пытон-переменная, 
py> obj1.Geometry.Position = test   # а здесь я должен реагировать на изменение
py> obj1.Geometry.Yaw = 10       # а здесь проверить есть ли Yaw для obj1       
Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 872


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #5 : Ноябрь 14, 2013, 09:24 »

Так а что мне даст статический член?
Здесь:
Код:
py> test = Position() 
py> obj1.Geometry.Position = test
ничего.
А здесь:
Код:
void py_set_x(Position* o, int value) 
{
  o->x = value;
  o->p->DoModifyX();   // p - указатель на данные приложения
}
позволит выполнить DoModifyX().
Ну, а по поводу
Цитировать
А что если данный экземпляр Geomеtry не имеет атрибута yaw? (а др экземпляр имеет).
я и в первый раз ничего не понял...
 
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Ноябрь 14, 2013, 15:22 »

позволит выполнить DoModifyX().
Если p - статический, то DoModifyX() будет выполняться всегда, то что он должен делать  Непонимающий

я и в первый раз ничего не понял...
Код:
py> obj.Geometry.Position.x = 1   # Ок если obj имеет флаг "implicit" иначе должна быть ошибка
py> obj.Geometry.yaw = 1       # Ок если obj имеет флаг "explicit" иначе должна быть ошибка
py> obj.Position.x = 1         # универсальный вариант, сам разбирается с флагом
Все 3 варианта должны поддерживаться. Все 3 присаивают одно и то же поле пытон-переменной, но в приложении соответствуют разным данным. Флаг implicit/explicit устанавливается юзером в приложении для каждого объекта индивидуально и не меняется во время выполнения скрипта

А так все здорово и пытон очарователен, вот только эти противные "мелочи"  Плачущий
Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 872


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #7 : Ноябрь 15, 2013, 10:38 »

Если p - статический, то DoModifyX() будет выполняться всегда, то что он должен делать  Непонимающий
хз. это ваша функция.
Цитировать
А так все здорово и пытон очарователен...
На этой ноте и закончим.
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Ноябрь 15, 2013, 13:16 »

Если p - статический, то DoModifyX() будет выполняться всегда, то что он должен делать  Непонимающий
хз. это ваша функция.
Я имел ввиду static один на всех, выскочить на модифицируемый объект приложения не удается

На этой ноте и закончим.
Да, видимо слишком специфично. Как-то сделал, не блеск, но работает. Спасибо за помощь
Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 872


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #9 : Ноябрь 16, 2013, 10:37 »

Вот еще, может, пригодится - шаблон для изготовления врапперов, я использую его по принципу "copy/paste/replace":
Код:
// шаблон декоратора. Наследует либо QObject, либо враппер базового класса
#include <QObject>
#include "$ClassType$.h"
#include "wrap_ed_objects.h"
//---------------------------------------------------------------------------

class $ClassType$Wrapper : public $BaseType$Wrapper {
    Q_OBJECT

public slots:
    // конструктор и деструктор
    $ClassType$* new_$ClassType$() { return new $ClassType$(); }
    void delete_$ClassType$($ClassType$* o) { delete o; }

    // эмуляторы свойств
    QString py_get_$Property$($ClassType$* o) { return o->$Property$; }
    void    py_set_$Property$($ClassType$* o, QString value) { o->$Property$ = value; }

    $PropertyType$* py_get_$Property$($ClassType$* o) { return &o->$Property$; }
    void    py_set_$Property$($ClassType$* o, $PropertyType$ value) { o->$Property$ = value; }
};
//---------------------------------------------------------------------------
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Ноябрь 16, 2013, 11:47 »

Вот еще, может, пригодится - шаблон для изготовления врапперов,
А как "запускаете сенокосилку"?
Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 872


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #11 : Ноябрь 16, 2013, 16:48 »

Да простят меня... Ну так:
1. Нужен враппер для класса Geometry.
2. Добавляю в проект класс C++ с именем GeometryWrapper.
3. Вместо объявления класса копирую туда указанный шаблон, в .cpp удаляю конструктор (там остается только #include "geometrywrapper.h"). Можно вообще cpp удалить, если методы враппера тривиальные.
4. Подсчитываю, сколько нужно эмулировать простых свойств ($Property$), сколько свойств с типом классов ($PropertyType$). В шаблоне повторяю пары get/set столько, сколько насчитал.
5. Делаю контекстную замену $ClassType$ на Geometry.
6. Если Geometry наследует класс, для которого есть враппер, заменяю $BaseType$ на него, иначе -на QObject.
7. Для каждого свойства заменяю $Property$ в паре get/set на имя этого свойства, например на posx, posy, posz.
8. Если есть свойства с типом классов, заменяю $PropertyType$ на нужный класс, например, Position.
Далее нужно зарегистрировать класс, для которого создан враппер.
Последнее - у меня все простые свойства имеют тип QString. Если у вас не так, значит, делаем еще замену типов.
Достоинство этого "метода" - тупость, а, значит, минимум ошибок. Можно и автоматизировать (кстати, в составе PythonQt есть генератор - не разбирался, может, и оно. Разберетесь - сообщите), но ради полсотни классов, для которых мне нужно было написать врапперы, было лень. пересчитал - оказалось, 70. нифига себе...
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Ноябрь 16, 2013, 19:21 »

но ради полсотни классов, для которых мне нужно было написать врапперы, было лень. пересчитал - оказалось, 70. нифига себе...
У меня 3 (делал все на пропердях), поэтому автоматизация не так актуальна Улыбающийся   

Да простят меня...
Понял, не буду больше надоедать Улыбающийся Спасибо
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.112 секунд. Запросов: 22.