从boostpython模块内部的pyside导入类
import classes from pyside inside of a boost python module?
我想使用PySide来定义基本的QT类以及C++和python之间的映射,但要在独立的python代码和使用boost::python的嵌入式python中这样做。
首先,模块定义和类返回QPointF:
QPointF X::getY() {
return QPointF();
}
BOOST_PYTHON_MODULE(myBoostPythonModule)
{
// is there some magic init/register commands to put here?
boost::python::api::object module = import("__main__");
boost::python::api::object name_space = module.attr("__dict__");
boost::python::exec("from PySide.QtCore import *",name_space,name_space);
boost::python::exec("import sys,osnprint(sys.modules)",name_space,name_space);
class_<X, boost::noncopyable>(
"X", init<const char*>())
.def("getY",&X::getY)
;
}
现在,应用程序的嵌入式python代码,最后一行是失败的地方,我想知道如何绕过:
execute("import myBoostPythonModule"); // OK
execute("x=myBoostPythonModule.X('foo')"); // OK
execute("w=QPointF()nprint(w)"); // OK
// PySide.QtCore.QPointF(0.000000, 0.000000)
execute("y=x.getY()"); // FAIL:
// TypeError: No to_python (by-value) converter found for C++ type: QPointF
这里发生了什么,我可以创建一个QPointF,但这个名称不知何故没有绑定在python和c++之间?我是不是在模块中遗漏了一些导入,让它从PySide导入?
PySide提供了与Shiboken的Qt绑定。Shiboken生成Python C API绑定,支持自己的类型转换系统。这些转换的知识存在于Shiboken生成的绑定中,而不是Python类型的系统中。因此,PySide知道如何将QPointF
对象转换为C++/Python;Python的类型系统没有。
当一个对象通过Boost.Python公开的函数转换时,Boost.Pathon将检查其注册表中是否有合适的类型转换器。这些转换器为Boost.Python提供了如何为通过Boost.Pathon公开的类型转换为C++/Python的知识。因此,当Boost.Pthon试图将QPointF
C++类型返回给Python时,它会抛出一个异常,因为转换尚未在Boost.PPython中注册。
这是带注释的代码:
import myBoostPythonModule
from PySide.QtCore import *
...
x=myBoostPythonModule.X('foo') # Boost.Python knows how to convert C++ X
# to Python X. Python's type system does not.
w=QPointF() # Shiboken knows how to convert C++ QPointF to
# Python QPointF. Python's type system does not.
print(w) # Shiboken knows how to represent C++ QPointF as
# a string.
y=x.getY() # Boost.Python knows how to invoke X::getY(),
# but only Shiboken knows how to convert C++
# QPointF to Python QPointF. Thus, the TypeError
# exception is raised.
可以用另一种实现方式来实现Boost.Python的转换器。在Shiboken类型转换器示例的基础上,下面是一个完整的Boost.Python转换器示例,它是用Shiboken的旧类型转换器实现的。我本想使用新的Shiboken类型转换器API,但我不清楚它是基于什么文档。
#include <iostream>
#include <boost/python.hpp>
/// @brief Mockup Complex class from Shiboken documentation.
class Complex
{
public:
Complex(double real, double imaginary)
: real_(real),
imaginary_(imaginary)
{}
double real() const { return real_; }
double imaginary() const { return imaginary_; }
private:
double real_;
double imaginary_;
};
/// @brief Mocked up Shiboken converter.
namespace Shiboken {
template <typename> struct Converter;
template <> struct Converter<Complex>
{
public:
// ...
static inline bool isConvertible(PyObject* pyObj)
{
std::cout << "Shiboken::Converter<Complex>::isConvertible()" << std::endl;
return PyComplex_Check(pyObj);
}
// ...
static inline PyObject* toPython(const Complex& cpx)
{
std::cout << "Shiboken::Converter<Complex>::toPython()" << std::endl;
return PyComplex_FromDoubles(cpx.real(), cpx.imaginary());
}
static inline Complex toCpp(PyObject* pyobj)
{
std::cout << "Shiboken::Converter<Complex>::toCpp()" << std::endl;
double real = PyComplex_RealAsDouble(pyobj);
double imaginary = PyComplex_ImagAsDouble(pyobj);
return Complex(real, imaginary);
}
};
} // namespace Shiboken
/// @brief Type used to convert a complex to Python.
struct complex_converter_to_python
{
static PyObject* convert(const Complex& c)
{
// Delegate to Shiboken.
std::cout << "complex_converter_to_python::convert()" << std::endl;
return Shiboken::Converter<Complex>::toPython(c);
}
};
/// @brief Type that registers a Python Complex type to C++
/// Complex when passing through Boost.Python.
struct complex_converter_from_python
{
/// @note Registers converter from a python complex to C++ complex.
complex_converter_from_python()
{
boost::python::converter::registry::push_back(
&complex_converter_from_python::convertible,
&complex_converter_from_python::construct,
boost::python::type_id<Complex>());
}
/// @brief Check if PyObject is a Complex.
static void* convertible(PyObject* object)
{
// Delegate to Shiboken. Based on the documentation, the
// isConvertible function is gone, so explicit checking may
// be required based on the version of Shiboken.
std::cout << "complex_converter_from_python::convertible()" << std::endl;
return Shiboken::Converter<Complex>::isConvertible(object)
? object
: NULL;
}
/// @brief Convert Python Complex to C++ Complex.
static void construct(
PyObject* object,
boost::python::converter::rvalue_from_python_stage1_data* data)
{
// Obtain a handle to the memory block that the Boost.Python
// converter has allocated for the C++ type.
namespace python = boost::python;
typedef python::converter::rvalue_from_python_storage<Complex>
storage_type;
void* storage = reinterpret_cast<storage_type*>(data)->storage.bytes;
// In-place construct a Complex type via copy-constructor, passing
// in a Complex created from Shiboken.
std::cout << "complex_converter_from_python::construct()" << std::endl;
data->convertible = new (storage) Complex(
Shiboken::Converter<Complex>::toCpp(object));
}
};
/// @brief Factory function used to exercise to-python conversion.
Complex make_complex(double real, double imaginary)
{
return Complex(real, imaginary);
}
/// @brief Printing function used to exercise from-python converison.
void print_complex(const Complex& c)
{
std::cout << "In print_complex: "
<< c.real() << ", "
<< c.imaginary() << std::endl;
}
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
// Register Complex from python converter.
complex_converter_from_python();
// Register Complex to python converter.
python::to_python_converter<
Complex,
complex_converter_to_python>();
python::def("make_complex", &make_complex);
python::def("print_complex", &print_complex);
}
及其用途:
>>> import example
>>> x = example.make_complex(4, 2)
complex_converter_to_python::convert()
Shiboken::Converter<Complex>::toPython()
>>> example.print_complex(x)
complex_converter_from_python::convertible()
Shiboken::Converter<Complex>::isConvertible()
complex_converter_from_python::construct()
Shiboken::Converter<Complex>::toCpp()
In print_complex: 4, 2
另一种方法虽然不是最优雅的方法,但可以使用Boost中公开的函数。Python使用boost::python::object
类型,并通过Python语句与对象接口。类似于:
boost::python::object X::getY()
{
return boost::python::exec("QPointF()", ...);
}
上面的代码将让Python实例化一个QPointF
Python对象,该对象将委托给Shiboken的类型系统。由于X::getY()
返回一个泛型对象,当对象句柄从C++转换到Python时,Boost.Python不会尝试执行类型转换。
根据前面的回复和我发现的其他信息,这里有一个有点通用的例程,允许像PySide.QtGui.QColor
参数这样的东西传递到boost::python
包装的c++方法中,该方法需要QColor&
输入参数:
template<class QtGuiClass,int SBK_BOGAN_IDX>
struct QtGui_from_python {
QtGui_from_python() {
qDebug()<<" registering type: " << typeid(this).name() << " in " << __FUNCTION__;
boost::python::converter::registry::push_back(
&convertible,
&construct,
boost::python::type_id<QtGuiClass>());
}
static void* convertible(PyObject* obj_ptr) {
if(!PyObject_TypeCheck(obj_ptr,
(PyTypeObject*)XSbkPySide_QtGuiTypes[SBK_BOGAN_IDX]))
{ qDebug()<<"Failed type check!?"; }
return obj_ptr;
}
static void construct( PyObject* obj_ptr,
bp::converter::rvalue_from_python_stage1_data* data)
{
void* storage = (
(boost::python::converter::rvalue_from_python_storage<QtGuiClass>*)
data)->storage.bytes;
SbkObject* result = reinterpret_cast<SbkObject*>(obj_ptr);
auto _ptr = (QtGuiClass*) (Shiboken::Object::cppPointer(
result,Py_TYPE(result)));
new (storage) QtGuiClass(*_ptr);
qDebug() << "__alloc'd " << typeid(*_ptr).name() <<" at "<<_ptr;
data->convertible = storage;
}
};
以及,从启动函数调用以上内容:
QtGui_from_python<QColor,SBK_QCOLOR_IDX>();
- 尝试导入pybind-opencv模块时出现libgtk错误
- 导入库可以跨dll版本工作吗
- 建议在运行时将带有类实例的列表从c++导入qml
- 导入/导出变量时出错
- 为什么导入Mixed native/CLR lib.dll的本机C++应用程序没有在Mixed lib.dll中的外部变
- 将QT项目导入Visual Studio 2019会给我带来很多LNK2001错误
- 是否可以将函数导入命名空间,但不能导出它?
- 如何将 CLion C++ 项目导入 Visual Studio?
- Python 3.8 不能与 Pybind11 一起导入 [Windows]
- 无法将标准库导入本机 android 项目中的头文件
- 尝试了解在导入的静态方法上使用删除方法时的错误
- 在 python 模块中导入子模块时PyImport_Import失败
- 将 C# DLL 导入 C++ 以用于 JNI
- 使用 QSslCertificate 在 Qt 中正确导入 pkcs12
- 在从Qt调用的Python脚本中导入OpenCV崩溃
- 编译boost_python扩展无法在 python 2.7 中导入
- 如何在安卓工作室中将c ++头文件从一个文件夹导入到另一个文件夹?
- Dll在同一解决方案中从 c# 项目导入到 c++ 项目
- C++20 使用 Visual Studio 编译模块:不编译或导入 ixx 文件
- 从boostpython模块内部的pyside导入类