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

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

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

Сообщений: 11445


Просмотр профиля
« : Октябрь 24, 2013, 11:11 »

Добрый день

Есть 2 вида скриптов. Первый применяется при действии пользователя внутри приложения, напр (псевдокод)
Цитировать
Object2.position = vec3(Object1.position.x, Object1.position.y, Object1.position.z + 100);
Теперь если пользователь интерактивно двигает Object1, то Object2 движется вместе с ним.

Скрипт второго типа как бы просто команда, вызывается пользователем напр из меню и отрабатывет 1 раз, псевдокод
Цитировать
Object1 = CreateObject("Sphere");
Object1.radius = 10;
Object1.move(100, 100, 100);
Пользователь должен иметь возможность создавать, редактировать и удалять скрипты из приложения.

Как бы Вы задумали такое UI (в принципе, функционал)? Какие должны быть бубочки, где и что они должны делать?

Спасибо
« Последнее редактирование: Октябрь 24, 2013, 11:38 от Igors » Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 872


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


Просмотр профиля
« Ответ #1 : Октябрь 24, 2013, 20:52 »

Для себя я выбрал такой вариант (см. картинку). Скрипты (Python) хранятся в БД, выбираем в списке (Хранилище сценариев), отображается в окне редактора. Можно создать, редактировать скрипт. В списке скрипты организованы в виде древовидного списка аналогично файловой системе.

Текущий скрипт можно исполнить. Результат - созданный объект (список объектов), который добавляется и отображается в таблице (вкладки ЭПД, ЭСИД), доступен для различных действий (просмотр, печать, редактирование, сохранение в файл и т.д.).

Ваш первый тип скриптов отличается от этого варианта тем, что скрипт можно в процессе исполнения программы динамически извлекать из БД по его id и исполнять (например, когда тащите объект). Легко реализуемо.

Поддержка скриптов - на PythonQt, взаимодействие программы и скриптов - через шлюз, основанный на врапперах классов объектов, используемых и в программе и в скриптах. В документации по PythonQt этого нет, но все просто, достаточно посмотреть пару примеров.
Шлюз обеспечивает функциональность, необходимую для работы с объектами.

Если нужно, могу предоставить ссылку на полный проект в исходниках, где есть и готовый виндовый исполняемый файл.
« Последнее редактирование: Октябрь 24, 2013, 21:03 от sergek » Записан

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

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Октябрь 25, 2013, 18:27 »

Проект не нужен, но все равно спасибо. Да, у Вас все норм (может тулбар здоровый как лапоть, ну то дело вкуса).  Мне держать в базе - не очень с руки. Приложение помещает свои плагины в определенные фолдера - ну и файлы скриптов по аналогиии, почему нет? "Локальные" скрипты проще сохранить в файле проекта. Дерево тоже как-то не лепится к моему случаю, т.к. в обозримом будущем не видно ни одного хоть какого-то "ветвления".

Понимаю что в Вашем случае это "то что надо", просто оно механически не переносится  Улыбающийся Спасибо
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


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

Поддержка скриптов - на PythonQt, взаимодействие программы и скриптов - через шлюз, основанный на врапперах классов объектов, используемых и в программе и в скриптах. В документации по PythonQt этого нет, но все просто, достаточно посмотреть пару примеров.
Подключил PythonQt и уже прорвался к "hello world" (т.е. могу выполнять простые скрипты из приложения).

Вопрос начинающего (пытона раньше никогда не видел). Вот есть такой скрипт
Цитировать
Object1.position.x = 0  # Object1 - объект основного приложния
Понятно что я могу сделать wrap для Object1, но как это сделать "на лету"? То есть экземпляров (таких как Object1) у меня могут быть тысячи, а в скрипте используется всего 1 - ну не должен же я врапить все тысячи перед каждым выполнением скрипта?

Спасибо  

Edit:
Или я должен действовать примерно так
Цитировать
prj.GetObject("Object 1").position.x = 0
А объект prj отврапить (текущий проект приложения всегда 1)
« Последнее редактирование: Октябрь 28, 2013, 13:59 от Igors » Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 872


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


Просмотр профиля
« Ответ #4 : Октябрь 29, 2013, 09:30 »

Цитировать
Object1.position.x = 0  # Object1 - объект основного приложния
Понятно что я могу сделать wrap для Object1, но как это сделать "на лету"? То есть экземпляров (таких как Object1) у меня могут быть тысячи, а в скрипте используется всего 1 - ну не должен же я врапить все тысячи перед каждым выполнением скрипта?
1) Обертка (wrapper) делается не для объекта, а для класса. Т.е. делаете враппер для своего класса, регистрируете в PythonQt, и можете создавать в скриптах сколько угодно объектов этого класса, работать с ними. Есть требование к классам, которые можно регистрировать в PythonQt - эти классы должны наследоваться от QObject.
2) Как правило, требуется возможность передачи данных из программы в Питон (имеется в виду встроенный в программу интерпретатор) и обратно. Такая возможность существует. Как лучше ее организовать, зависит от задачи.
Я не все возможности PythonQt знаю, только те, которые мне потребовались для реализации моего проекта. Поэтому лучше вам сформулировать, что нужно, а я попробую помочь.
3) Посмотрите доку http://pythonqt.sourceforge.net/index.html, в частности, раздел "Developer", примеры. Но документация не включает некоторые возможности, например, в ней не описан способ эмуляции свойств (obj.property = v). Можно почитать конференцию Флориана: http://sourceforge.net/p/pythonqt/discussion/631392.
Записан

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

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Октябрь 29, 2013, 10:08 »

Но документация не включает некоторые возможности, например, в ней не описан способ эмуляции свойств (obj.property = v). Можно почитать конференцию Флориана: http://sourceforge.net/p/pythonqt/discussion/631392.
Именно на этом я сейчас застрял Улыбающийся Если нетрудно, укажите топик конференции (пока не нашел). Спасибо

Обертка (wrapper) делается не для объекта, а для класса.
То ясно, просто сейчас в приложении есть какой-то самопальный скриптинг который позволяет обращаться "Object1" при условии что Object1 есть в приложении. В пытоне так нельзя, переменная должна быть объявлена присваиванием (если не так - поправьте)

Большинство объектов у меня статично, их данные известны и неизменны. Но не все - есть плагины которые создают свои данные динамически. Напр в UI плагина пользователь выбрал "сфера" - появился параметр "радиус". Потом поменял на "куб" - уже др. параметры. Я могу это оформить методами (код скрипта)
Цитировать
obj.setParam("radius", 10);
Но пользователю это не очень удобно, он хочет так
Цитировать
obj.radius = 10;
Как бы это порешать?
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #6 : Октябрь 29, 2013, 10:28 »

Именно на этом я сейчас застрял Улыбающийся Если нетрудно, укажите топик конференции (пока не нашел). Спасибо
http://sourceforge.net/p/pythonqt/discussion/631392/thread/278533e7/

В пытоне так нельзя, переменная должна быть объявлена присваиванием (если не так - поправьте)
Нужно регистрировать все необходимые объекты в контексте питона, тогда к ним можно будет обращаться из скрипта.
Есть 100500 плюсовых объектов, все нужно зарегистрировать.
Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 872


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


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

Но документация не включает некоторые возможности, например, в ней не описан способ эмуляции свойств (obj.property = v). Можно почитать конференцию Флориана: http://sourceforge.net/p/pythonqt/discussion/631392.
Именно на этом я сейчас застрял Улыбающийся Если нетрудно, укажите топик конференции (пока не нашел). Спасибо
http://sourceforge.net/p/pythonqt/discussion/631392/thread/278533e7/

Но пользователю это не очень удобно, он хочет так
Цитировать
obj.radius = 10;
Как бы это порешать?

Простейший пример:

Исходный класс:
Код:
class CPartInfo
{
public:
    // Methods & Properties
    QString PartNo;
    QString PartQuantity;
    QString PartAggregateID;
};
Обертка для него:
Код:
class CPartInfoWrapper : public QObject {
    Q_OBJECT

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

    // эмуляторы свойств
    QString py_get_PartNo(CPartInfo* o) { return o->PartNo; }
    void    py_set_PartNo(CPartInfo* o, QString value) { o->PartNo = value; }
    QString py_get_PartQuantity(CPartInfo* o) { return o->PartQuantity; }
    void    py_set_PartQuantity(CPartInfo* o, QString value) { o->PartQuantity = value; }
    QString py_get_PartAggregateID(CPartInfo* o) { return o->PartAggregateID; }
    void    py_set_PartAggregateID(CPartInfo* o, QString value) { o->PartAggregateID = value; }
};
Регистрация обертки в PythonQt:
Код:
    // инициализация библиотеки PythonQt
    PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);
    // экземпляр Питона
    context = PythonQt::self()->getMainModule();

    // регистрация прикладных классов
    PythonQt::self()->registerCPPClass("CPartInfo", "","QtCore", PythonQtCreateObject<CPartInfoWrapper>);
    ...
    // импорт всех зарегистрированных классов
    context.evalScript("from PythonQt.QtCore import *");
Если членами классов являются объекты других классов, нужны обертки для них, регистрация, а свойства делаются через указатели:
Код:
    CDepartmentalInfo* py_get_DepartmentalInfo(CED101* o) { return &o->DepartmentalInfo; }
    void    py_set_DepartmentalInfo(CED101* o, CDepartmentalInfo value) { o->DepartmentalInfo = value; }
    CEDRefID* py_get_InitialED(CED101* o) { return &o->InitialED; }
    void    py_set_InitialED(CED101* o, CEDRefID value) { o->InitialED = value; }
В скрипте можно так:
Код:
>part=CPartInfo()
>part.PartNo = '123'
>print part.PartNo
Да, прошу не пинать, что переменные именуются с прописных букв - это отрыжка исходной постановки задачи, основанной на альбоме форматов...  Грустный
« Последнее редактирование: Октябрь 29, 2013, 10:40 от sergek » Записан

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

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Октябрь 29, 2013, 11:19 »

Работает, спасибо! Оказывается есть "волшебные слова" py_get_ и py_set_  Улыбающийся

Есть 100500 плюсовых объектов, все нужно зарегистрировать.
Надо - так надо, но как мне сделать это динамически, на этапе выполнения? Пусть юзверь написал в скрипте
Цитировать
obj = prj.GetObject("Object1")
Вероятно, сейчас будет обращение к атрибутам Object1, и мне известны все их имена и типы данных. Но я не могу их знать до выполнения. Напр в любой момент юзверь может подключить файл плагина который мне был неизвестен но который объявит свои пропердии. Как бы вот тут разрулить?

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

Сообщений: 872


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


Просмотр профиля
« Ответ #9 : Октябрь 29, 2013, 11:36 »

Надо - так надо, но как мне сделать это динамически, на этапе выполнения? Пусть юзверь написал в скрипте
Цитировать
obj = prj.GetObject("Object1")
Вероятно, сейчас будет обращение к атрибутам Object1, и мне известны все их имена и типы данных. Но я не могу их знать до выполнения. Напр в любой момент юзверь может подключить файл плагина который мне был неизвестен но который объявит свои пропердии. Как бы вот тут разрулить?
Легко. Можно регистрировать не только классы, но и объекты. В этом случае в скриптах эти объекты сразу доступны для использования, а в программе - результат их использования. Примерно так:
Код:
    // объект
    CScriptGateway gate;
    QString gatewayObjName = "gate";

    // регистрация в Питоне класса
    PythonQt::self()->registerClass(&CScriptGateway::staticMetaObject, "QtCore", PythonQtCreateObject<CScriptGateway>);
    // регистрация объекта
    context.addObject(gatewayObjName,&gate);
В скрипте сразу обращаемся к объекту (без использования конструктора):
Код:
>gate.prop1 = val;
>print gate.prop1
А в программе gate.prop1 примет значение val. Наверное Подмигивающий
Только для случая регистрации объектов необходимо, чтобы класс этого объекта (CScriptGateway) должен быть порожден от QObject.
Записан

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

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Октябрь 29, 2013, 13:04 »

Легко. Можно регистрировать ...
Да, работает! И для "цепочек" тоже

Код
C++ (Qt)
CPyProject * prj = new CPyProject();
 
QObject * cls = new QObject();
cls->setProperty("prop2", QVariant(1.0));
 
QVariant var = qVariantFromValue(cls);
prj->setProperty("prop1", var);
 
PythonQt::self()->registerClass(&CPyProject::staticMetaObject, "", PythonQtCreateObject<CPyProject>);
 
theModules[0].addObject("prj", prj);
 
После этого я могу писать в скрипте
Код:
print prj.ptop1.prop2
Круто (червона рута). А могу ли я удалить cls (или использовать локальный) - или этот экземпляр должен существовать?

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

Сообщений: 872


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


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

А могу ли я удалить cls (или использовать локальный) - или этот экземпляр должен существовать?
Пока используете его в скрипте, должен, разумеется. Поэтому объект должен быть в пределах видимости модуля, гда используется Питоновский скрипт.
А вот потом - хз. Если есть addObject, то, скорее всего, должен быть что-нибудь вроде removeObject...
Записан

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

Сообщений: 4350



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

А могу ли я удалить cls (или использовать локальный) - или этот экземпляр должен существовать?
Конечно, для работы с ним из скрипта он должен существовать. Но можно указать питону, что бы он сам уничтожил этот объект, когда последняя ссылка на него исчезнет. Или наоборот, не уничтожил объект, который в скрипте уже не используется, но необходим в хост-программе.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #13 : Октябрь 29, 2013, 17:10 »

Также я могу комбинировать поля и методы, напр
Код:
print prj.prop1.prop2
print prj.prop1.value()
Однако хотелось бы создавать prop2 динамически, в тот момент когда произошло (скриптовое) обращение к prop1 (возможно кешируя). А иначе я вынужден заряжать и отслеживать все пропердии на все случаи жизни (хотя скрипт может обратится всего к 1-2). Но как отследить "вызов prop1"?

Спасибо
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #14 : Октябрь 29, 2013, 17:31 »

Однако хотелось бы создавать prop2 динамически, в тот момент когда произошло (скриптовое) обращение к prop1 (возможно кешируя).
Ну так у вас вызовется метод объекта вашего врапера, при обращении к prop1. В нем и создавайте динамически объект.
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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