Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Скриптуем С++ приложение, связка С++ <-> Python 
:(
    Опции темы
Lеstat
  Дата 28.7.2009, 16:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 76
Регистрация: 28.12.2005
Где: Москва

Репутация: нет
Всего: нет



Возникла задача добавить к приложению возможность выполнять скрипты.
Для примера могу привести modo.
Думаю в приложении любой контролл, виджет и т.д. отправляет команду с параметрами скриптовому движку для изменения чего-либо, получения данных и т.д. и получает результат выполнения этой команды.

На данный момент прикрутил выполнение скриптов из С++ кода, но не понимаю как собрать все в кучу... 

Приведу очень простой пример: 

Вот короткая программа в которой я создаю Qt'ешное окно в С++, затем я хочу создать еще одно окно в моем же приложении, но на питоне.
В коде видно, что создается новый экземпляр QApplication в питоне, и работа ведется уже с ним. Я считаю это неправильным. Я должен работать с app созданным в C++ коде.
Мне нужно как-то передать указатель на экземпляр класса созданного в С++ в питон. Т.к. питон знает описание класса, например, Qwidget (т.к. подключен PyQt), то я смогу изменить заголовок окна window созданного в С++ коде... но проблема в том, что я не понимаю как передать указатель или реализовать это с помощью каких-нибудь других механизмов. Таким образом я не смогу связать С++ и питон. Просто выполняю скрипт из проги и все(

Код

#include <QApplication>
#include <QWidget>

#include <stdlib.h>
#include <iostream>

// чтобы собралось в дебаге без python30_d.lib
#ifndef _DEBUG
#include "python.h"
#else
#undef _DEBUG
#include "python.h"
#define _DEBUG
#endif

// конвертирование char** в wchar_t**
wchar_t** argvToWchar_t(int argc, char **argv)
{
    wchar_t** res = new wchar_t*[argc];
    for (int i = 0; i < argc; i++)
    {
        int len = (int)strlen(argv[i]) + 1; 
        res[i] = new wchar_t[len];
        mbstowcs(res[i], argv[i], len);
    }
    return res;
}

int main(int argc, char *argv[])
{
    setlocale(LC_ALL, "Russian");

    QApplication app(argc, argv);

    // тестовое окно
    QWidget *window = new QWidget();
    window->resize(300, 200);
    window->setWindowTitle("Native window");
    window->show();

    /* Инициализация интерпретатора */
    Py_Initialize();
    PySys_SetArgv(argc, argvToWchar_t(argc, argv));

    char* init_srcript =    "import sys \n"
                            "import PyQt4 \n"
                            "from PyQt4 import QtCore, QtGui \n"
                            ;

    char* testPyQt4 =    "def testPyQt4(): \n"
                        "    app = QtGui.QApplication(sys.argv) \n"
                        "    widget = QtGui.QWidget() \n"
                        "    widget.resize(250, 150) \n"
                        "    widget.setWindowTitle('Script window') \n"
                        "    widget.show() \n"
                        "    sys.exit(app.exec_()) \n"
                        ;

    PyRun_SimpleString(init_srcript);
    PyRun_SimpleString(testPyQt4);
    PyRun_SimpleString("testPyQt4() \n");

    /* Основной цикл Qt */
    bool returnValue = app.exec();

    /* Завершение работы интерпретатора */
    Py_Finalize();

    return returnValue;
}



Насколько я понимаю, весь движок,  приходится делать как С++'сный модуль питона, а exe'шка всего лишь выполняет запуск функции инициализации этой либы.

Возможно ли вызывать методы уже созданных экземпляров классов в С++ коде из питона?
Как связать экземпляры Qt'ешных классов созданных в С++ коде с питоном? Ведь и питон и С++ знают описания классов.

Читал про py++, boost.python, swig. Все эти штуки требуют написания интерфейса, кроме пожалуй Py++... он вроде сам генерирует, но сделать с ним я ничего пока не смог.

Допустим интерфейс создан и я могу питоновскими командами создавать/изменять/работать с объектами своей длл'ки из питона, но как взаимодействовать с объектами С++'сного кода? 

Объясните, пожалуйста, как вызвать метод окна window, созданного в С++ коде моего примера из питона. 
 
PM MAIL ICQ   Вверх
powerfox
Дата 28.7.2009, 17:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


I wanna fork()
****


Профиль
Группа: Комодератор
Сообщений: 3990
Регистрация: 1.10.2005
Где: Санкт-Петербург

Репутация: 1
Всего: 97



Цитата(Lеstat @  28.7.2009,  17:25 Найти цитируемый пост)
Читал про py++, boost.python, swig. Все эти штуки требуют написания интерфейса, кроме пожалуй Py++... он вроде сам генерирует, но сделать с ним я ничего пока не смог.

Насколько я понял, то Kross бы вас удовлетворил на все 100. По идее, под Windows с ним не должно быть проблем, но он, если мне не изменяет память, довольно сильно завязан на библиотеки KDE.

Кстати, я почем именно питон нужен? QtScript, вроде бы, довольно неплох.

Это сообщение отредактировал(а) powerfox - 28.7.2009, 17:10


--------------------
user posted image
PM WWW   Вверх
Amp
Дата 28.7.2009, 18:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 886
Регистрация: 17.2.2009

Репутация: нет
Всего: 17



Цитата(powerfox @  28.7.2009,  17:07 Найти цитируемый пост)
Кстати, я почем именно питон нужен? QtScript, вроде бы, довольно неплох.

Да, тоже думаю, что надо обратить на QtScript внимание, раз приложение Qt-based. У самого руки все чешутся его пощупать smile
PM MAIL   Вверх
Lеstat
Дата 28.7.2009, 19:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 76
Регистрация: 28.12.2005
Где: Москва

Репутация: нет
Всего: нет



Amppowerfox, читал немного про Qt Script, но думаю нужно использовать питон. 
Приложение на самом деле на wxWidgets сейчас, просто когда Qt стала LGPL стал присматриваться в сторону Qt.
Просто так взять и сразу все переписать на Qt с их скриптами довольно проблематично. Вобще не хотелось бы привязываться к Qt намертво. 
Программа предназначена для визуализации рассчетов. Скрипты в моем случае нужны не только для создания интерфейса, возможно даже в большей степени для  того чтобы рулить движком визуализации.
Сейчас чтобы настраивать все это дело нужно делать очень много менюшек, чтобы все подкручивать руками. Это не удобно.
Настраивать некоторые вещи в коде намертво нежелательно. Выносить в конфигии тоже, мне кажется, не лучший вариант... а вот скрипты по аналогии с modo, 3dsmax, maya, всякими CAD'ами и т.д. было бы очень хорошим решением!

Пока хочу получить возможность создавать/добавлять интерфейс приложения без компиляции всего проекта. Поэтому и начал возиться с Qt и PyQt.
Пытаюсь сделаю некий шаблон проскриптованного интерфейса...

Про Kross слышу в первый раз, посмотрю что за штука, Спасибо!
PM MAIL ICQ   Вверх
powerfox
Дата 28.7.2009, 20:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


I wanna fork()
****


Профиль
Группа: Комодератор
Сообщений: 3990
Регистрация: 1.10.2005
Где: Санкт-Петербург

Репутация: 1
Всего: 97



Цитата(Lеstat @  28.7.2009,  20:55 Найти цитируемый пост)
Про Kross слышу в первый раз, посмотрю что за штука, Спасибо! 

Это то, что вам нужно — 100%. Вопрос лишь в том, как это всё работает в винде (должно работать, KDE под виндой вполне нормально пашет), и в том, какие зависимости вы можете себе позволить (Kross может тянуть за собой kdelibs).
Возможности Kross: http://techbase.kde.org/Development/Tutorials#Kross


--------------------
user posted image
PM WWW   Вверх
Lеstat
Дата 11.10.2009, 12:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 76
Регистрация: 28.12.2005
Где: Москва

Репутация: нет
Всего: нет



powerfox, с кроссом так и не разобрался, немного продвинулся в другом направлении)

Дублирую свой пост с другого форума... может тутор кому пригодится, да и мне кто поможет.



Пытаюсь сделать поддержку приложением питоновских скриптов.

На данный момент связал С++ классы с питоном использую SWIG.

Думаю информация будет полезной для сообщества, напишу подробнее о том как использовал SWIG.
Вот простой пример, исходники на С++:

example.hpp
Код
#pragma once
#include <string>

class A
{
public:
    A(void);
    std::string getStr(void);
};

example.cpp
Код
#include "example.hpp"

A::A(void) { }
std::string A::getStr(void) {
    std::string str("Hello, World!");
    return str;
}

Для использования SWIG'а пишу example.i
Код
%module example
%{
    #include "example.hpp"
%}
 
%include "std_vector.i"
%include "std_string.i"
 
%include "example.hpp"

Далее нужно сгенерировать исходники с помощью SWIG и откомпилировать их.
Компилирую с помощью Visual Studio 2009 из командной строки.
Для этого написал bat файл.
Код
:: Запускаю SWIG
"C:\Program Files\SWIG\swigwin-1.3.40\swig.exe" -python -c++ example.i

@echo off
:: Устанавливаю переменные для работы cl.exe
call "C:\Program Files\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"
:: Собираю исходники в DLL, которую сохраняю с расширением *.pyd
"C:\Program Files\Microsoft Visual Studio 9.0\VC\bin\cl.exe" example_wrap.cxx example.cpp -I "C:\Python26\include" /link /OUT:"_example.pyd" /DLL /LIBPATH:"C:\Python26\libs"

:: Удаляю мусор
rm *.exp
rm *.lib
rm *.obj
rm *_wrap.cxx
rm *.pyc
pause

Теперь если выполнить 
Код
>>> import example
>>> x = example.A()
>>> print x.getStr()
Hello, World!
>>>

Как видим все работает!





Далее мне хотелось бы использовать в питоне объкты, которые созданы и работают в С++ коде.
Например, пишу такой main.cpp:

Код
#include <stdlib.h>
#include <iostream>
#include <string>
#include <python.h>

#include "example.hpp"


int main(int argc, char *argv[])
{
    setlocale(LC_ALL, "Russian");
    A *cppx = new A();


    Py_Initialize();
    PyRun_SimpleString("import example");

    // тут нужно что-то сделать чтобы связать cppx и питон

    PyRun_SimpleString("print cppx.getStr()");
    Py_Finalize();

    system("pause");
    return EXIT_SUCCESS;
}

Вот теперь мне нужно передать указатель в питоновский скрипт, чтобы питон работал не с "x = example.A()" как в примере выше, а с уже созданным в C++ коде объектом cppx.
Подскажите как их связать и возможно ли это вообще.
Ведь питон теперь знает что такое класс A... он в модуле example.
Спасибо!

Это сообщение отредактировал(а) Lеstat - 11.10.2009, 14:46
PM MAIL ICQ   Вверх
Lеstat
Дата 11.10.2009, 16:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 76
Регистрация: 28.12.2005
Где: Москва

Репутация: нет
Всего: нет



Вот кое-какие продвижения, но с использованием Boost.Python
На данным момент проблема, можно сказать, решена!
В коде не все понятно, но работает!

Вот исходник:
Код
#include <stdlib.h>
#include <iostream>

#define BOOST_PYTHON_STATIC_LIB
#include <boost/python.hpp>
using namespace boost::python;

class CppClass {
public:
    CppClass()
    {
        t = 0;
    }
    int getNum() {
        return t;
    }
    void inc()
    {
        t++;
    }
private: 
    int t;
};

int main( int argc, char ** argv ) 
{
    setlocale(LC_ALL, "Russian");
    try 
    {
        Py_Initialize();

        object main_module((handle<>(borrowed(PyImport_AddModule("__main__")))));

        object main_namespace = main_module.attr("__dict__");
        main_namespace["CppClass"] = class_<CppClass>("CppClass")
                                                        .def("getNum",&CppClass::getNum)
                                                        .def("inc",&CppClass::inc);

        CppClass *cpp = new CppClass();

        main_namespace["cpp"] = ptr(cpp);

        PyRun_String( "print \"Python: \", cpp.getNum()\n", 
            Py_file_input, main_namespace.ptr(), main_namespace.ptr());

        std::cout << "C++ inc()" << std::endl;
        cpp->inc();

        PyRun_String( "print \"Python: \", cpp.getNum()\n"
            "cpp.inc()\n"
            "print \"Python inc()\" \n"
            "print \"Python: \", cpp.getNum()\n",
            Py_file_input, main_namespace.ptr(), main_namespace.ptr());

        std::cout << "C++: " << cpp->getNum() << std::endl;
        std::cout << "C++ inc()" << std::endl;
        cpp->inc();

        PyRun_String( "print \"Python: \", cpp.getNum()\n",
            Py_file_input, main_namespace.ptr(), main_namespace.ptr() );

        Py_Finalize();
    } 
    catch( error_already_set ) 
    {
        PyErr_Print();
    }

    system("pause");
    return EXIT_SUCCESS;
}


На выходе получаем:
Код
Python:  0
C++ inc()
Python:  1
Python inc()
Python:  2
C++: 2
C++ inc()
Python:  3
Для продолжения нажмите любую клавишу . . .


Если кто-нибудь предложит вариант с использованием SWIG о котором я писал выше буду очень благодарен!
PM MAIL ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Python: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0954 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.