437 lines
12 KiB
C++
437 lines
12 KiB
C++
#include "pythonhandler.h"
|
||
#include <QCoreApplication>
|
||
#include <QFile>
|
||
#include <QProcessEnvironment>
|
||
|
||
PythonHandler::PythonHandler(QObject *parent)
|
||
: QObject(parent)
|
||
, m_initialized(false)
|
||
{
|
||
}
|
||
|
||
PythonHandler::~PythonHandler()
|
||
{
|
||
finalize();
|
||
}
|
||
|
||
PythonHandler *PythonHandler::getInstance()
|
||
{
|
||
static PythonHandler ref;
|
||
return &ref;
|
||
}
|
||
|
||
bool PythonHandler::initialize()
|
||
{
|
||
if (m_initialized) {
|
||
return true;
|
||
}
|
||
|
||
// 获取程序所在目录
|
||
QString appDir = QCoreApplication::applicationDirPath();
|
||
QString strPy= appDir + "/" + PYTHON_VER;
|
||
setupEnvironment(strPy);
|
||
strPy.toStdWString().c_str();
|
||
// 初始化Python解释器
|
||
Py_Initialize();
|
||
|
||
if (!Py_IsInitialized()) {
|
||
qDebug() << "Python初始化失败!";
|
||
return false;
|
||
}
|
||
|
||
// 添加Python脚本路径 - 使用绝对路径会更可靠
|
||
QString currentPath = QCoreApplication::applicationDirPath();
|
||
QString scriptPath = currentPath + "/python_scripts";
|
||
|
||
// QString strPy= currentPath + "/" + PYTHON_VER;
|
||
// QString scriptPython2 = strPy + "/DLLs";
|
||
// QString scriptPython3 = strPy + "/Lib";
|
||
// QString scriptPython4 = strPy + "/lib/site-packages";
|
||
// emit addLog(scriptPath);
|
||
QString pythonCode = QString(
|
||
"import sys\n"
|
||
"import os\n"
|
||
"sys.path.append('%1')\n"
|
||
"print('========== Python 调试信息 ==========')\n"
|
||
"print('当前工作目录:', os.getcwd())\n"
|
||
"print('exepath:', sys.executable)\n"
|
||
"print('Python 搜索路径:')\n"
|
||
"for p in sys.path:\n"
|
||
" print(' -', p)\n"
|
||
"print('======================================')\n"
|
||
).arg(scriptPath);
|
||
// emit addLog(pythonCode);
|
||
PyRun_SimpleString(pythonCode.toStdString().c_str());
|
||
|
||
m_initialized = true;
|
||
return true;
|
||
}
|
||
|
||
void PythonHandler::setupEnvironment(QString strPy)
|
||
{
|
||
// 使用 Qt 的方式设置环境变量
|
||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||
|
||
// 设置 PYTHONHOME
|
||
qputenv("PYTHONHOME", strPy.toLocal8Bit());
|
||
|
||
// 设置 PYTHONPATH
|
||
QString pythonPath = strPy + "/Lib;" + strPy + "/lib/site-packages;" + strPy + "/DLLs;";
|
||
qputenv("PYTHONPATH", pythonPath.toLocal8Bit());
|
||
|
||
// 修改 PATH(添加程序目录)
|
||
QString currentPath = QString::fromLocal8Bit(qgetenv("PATH"));
|
||
QString newPath = strPy + "/DLLs;" + currentPath;
|
||
qputenv("PATH", newPath.toLocal8Bit());
|
||
|
||
qDebug() << "Environment:";
|
||
qDebug() << "PYTHONHOME:" << qgetenv("PYTHONHOME");
|
||
qDebug() << "PYTHONPATH:" << qgetenv("PYTHONPATH");
|
||
}
|
||
|
||
void PythonHandler::finalize()
|
||
{
|
||
if (m_initialized) {
|
||
Py_Finalize();
|
||
m_initialized = false;
|
||
}
|
||
}
|
||
|
||
PyObject* PythonHandler::qVariantToPythonObject(const QVariant &value)
|
||
{
|
||
switch (value.type()) {
|
||
case QVariant::Int:
|
||
return PyLong_FromLong(value.toInt());
|
||
case QVariant::Double:
|
||
return PyFloat_FromDouble(value.toDouble());
|
||
case QVariant::String:
|
||
return PyUnicode_FromString(value.toString().toStdString().c_str());
|
||
case QVariant::List: {
|
||
QVariantList list = value.toList();
|
||
PyObject* pyList = PyList_New(list.size());
|
||
for (int i = 0; i < list.size(); ++i) {
|
||
PyList_SetItem(pyList, i, qVariantToPythonObject(list[i]));
|
||
}
|
||
return pyList;
|
||
}
|
||
case QVariant::Bool:
|
||
return PyBool_FromLong(value.toBool() ? 1 : 0);
|
||
default:
|
||
return Py_None;
|
||
}
|
||
}
|
||
|
||
QVariant PythonHandler::pythonObjectToQVariant(PyObject *obj)
|
||
{
|
||
if (!obj) {
|
||
qDebug() << "pythonObjectToQVariant: 输入对象为NULL";
|
||
return QVariant();
|
||
}
|
||
|
||
qDebug() << "pythonObjectToQVariant: 转换类型" << Py_TYPE(obj)->tp_name;
|
||
|
||
if (PyLong_Check(obj)) {
|
||
long long value = PyLong_AsLongLong(obj);
|
||
if (PyErr_Occurred()) {
|
||
PyErr_Clear();
|
||
return QVariant();
|
||
}
|
||
qDebug() << "转换为整数:" << value;
|
||
return QVariant(value);
|
||
}
|
||
else if (PyFloat_Check(obj)) {
|
||
double value = PyFloat_AsDouble(obj);
|
||
qDebug() << "转换为浮点数:" << value;
|
||
return QVariant(value);
|
||
}
|
||
else if (PyBool_Check(obj)) {
|
||
bool value = (obj == Py_True);
|
||
qDebug() << "转换为布尔值:" << value;
|
||
return QVariant(value);
|
||
}
|
||
else if (PyUnicode_Check(obj)) {
|
||
QString value = QString::fromUtf8(PyUnicode_AsUTF8(obj));
|
||
qDebug() << "转换为字符串:" << value;
|
||
return QVariant(value);
|
||
}
|
||
else if (PyList_Check(obj)) {
|
||
QVariantList list;
|
||
Py_ssize_t size = PyList_Size(obj);
|
||
qDebug() << "转换为列表,大小:" << size;
|
||
|
||
for (Py_ssize_t i = 0; i < size; ++i) {
|
||
PyObject* item = PyList_GetItem(obj, i);
|
||
if (item) {
|
||
list.append(pythonObjectToQVariant(item));
|
||
} else {
|
||
list.append(QVariant());
|
||
}
|
||
}
|
||
return list;
|
||
}
|
||
else if (PyTuple_Check(obj)) {
|
||
QVariantList list;
|
||
Py_ssize_t size = PyTuple_Size(obj);
|
||
qDebug() << "转换为元组,大小:" << size;
|
||
|
||
for (Py_ssize_t i = 0; i < size; ++i) {
|
||
PyObject* item = PyTuple_GetItem(obj, i);
|
||
if (item) {
|
||
list.append(pythonObjectToQVariant(item));
|
||
} else {
|
||
list.append(QVariant());
|
||
}
|
||
}
|
||
return list;
|
||
}
|
||
else if (PyDict_Check(obj)) {
|
||
QVariantMap map;
|
||
PyObject* pKeys = PyDict_Keys(obj);
|
||
Py_ssize_t size = PyList_Size(pKeys);
|
||
qDebug() << "转换为字典,大小:" << size;
|
||
|
||
for (Py_ssize_t i = 0; i < size; ++i) {
|
||
PyObject* pKey = PyList_GetItem(pKeys, i);
|
||
PyObject* pValue = PyDict_GetItem(obj, pKey);
|
||
|
||
if (pKey && pValue && PyUnicode_Check(pKey)) {
|
||
QString key = QString::fromUtf8(PyUnicode_AsUTF8(pKey));
|
||
map[key] = pythonObjectToQVariant(pValue);
|
||
}
|
||
}
|
||
Py_DECREF(pKeys);
|
||
return map;
|
||
}
|
||
else if (obj == Py_None) {
|
||
qDebug() << "转换为None";
|
||
return QVariant();
|
||
}
|
||
else {
|
||
qDebug() << "未知类型,返回空QVariant";
|
||
return QVariant();
|
||
}
|
||
}
|
||
|
||
QString PythonHandler::capturePythonError() {
|
||
QString errorMsg;
|
||
|
||
PyObject *ptype, *pvalue, *ptraceback;
|
||
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
|
||
|
||
if (pvalue) {
|
||
PyObject* pstr = PyObject_Str(pvalue);
|
||
if (pstr) {
|
||
errorMsg = QString::fromUtf8(PyUnicode_AsUTF8(pstr));
|
||
Py_DECREF(pstr);
|
||
}
|
||
}
|
||
|
||
// 清理
|
||
Py_XDECREF(ptype);
|
||
Py_XDECREF(pvalue);
|
||
Py_XDECREF(ptraceback);
|
||
|
||
return errorMsg;
|
||
}
|
||
|
||
QVariant PythonHandler::executeScript(const QString &scriptPath,
|
||
const QString &functionName,
|
||
const QVariantList &args,
|
||
float* outAtt0all,
|
||
int nlen)
|
||
{
|
||
if (!m_initialized && !initialize()) {
|
||
return QVariant();
|
||
}
|
||
|
||
// 获取全局字典
|
||
PyObject* pModule = nullptr;
|
||
PyObject* pFunc = nullptr;
|
||
PyObject* pArgs = nullptr;
|
||
PyObject* pResult = nullptr;
|
||
QVariant result;
|
||
|
||
// 导入模块
|
||
QString moduleName = scriptPath;
|
||
if (moduleName.endsWith(".py")) {
|
||
moduleName.chop(3);
|
||
}
|
||
// pModule = PyImport_ImportModule("numpy");
|
||
// if (!pModule) {
|
||
// QString error = capturePythonError();
|
||
// qDebug() << "Python error:" << error;
|
||
//
|
||
// PyErr_Print();
|
||
// emit addLog("无法导入Python模块:" + moduleName);
|
||
// return QVariant();
|
||
// }
|
||
pModule = PyImport_ImportModule(moduleName.toStdString().c_str());
|
||
|
||
if (!pModule) {
|
||
QString error = capturePythonError();
|
||
qDebug() << "Python error:" << error;
|
||
|
||
//PyErr_Print();
|
||
emit addLog("无法导入Python模块:" + moduleName);
|
||
return QVariant();
|
||
}
|
||
|
||
// 获取函数
|
||
pFunc = PyObject_GetAttrString(pModule, functionName.toStdString().c_str());
|
||
|
||
if (!pFunc || !PyCallable_Check(pFunc)) {
|
||
if (PyErr_Occurred()) {
|
||
PyErr_Print();
|
||
}
|
||
emit addLog("无法找到函数:" + functionName);
|
||
Py_XDECREF(pFunc);
|
||
Py_DECREF(pModule);
|
||
return QVariant();
|
||
}
|
||
|
||
// 构建参数
|
||
pArgs = PyTuple_New(args.size());
|
||
for (int i = 0; i < args.size(); ++i) {
|
||
PyTuple_SetItem(pArgs, i, qVariantToPythonObject(args[i]));
|
||
}
|
||
|
||
// 调用函数
|
||
pResult = PyObject_CallObject(pFunc, pArgs);
|
||
if (pResult) {
|
||
if(outAtt0all)
|
||
{
|
||
PyObject* array1 = PyTuple_GetItem(pResult, 0);
|
||
double dR = PyFloat_AsDouble(PyTuple_GetItem(pResult, 1)); // 获取double
|
||
// // 将numpy数组转换为C++数组(例如使用numpy的API)
|
||
// PyArrayObject* arr1 = (PyArrayObject*)PyArray_FromAny(array1, NULL, 0, 0, NPY_ARRAY_CARRAY, NULL);
|
||
PyArrayObject* arr1 = (PyArrayObject*)array1;
|
||
double* data1 = (double*)PyArray_DATA(arr1);
|
||
|
||
int len = PyArray_DIM(arr1, 0); // 获取数组长度
|
||
if (len>nlen)
|
||
len = nlen;
|
||
for (int i = 0; i < len; i++) {
|
||
outAtt0all[i] = data1[i];
|
||
}
|
||
#ifdef _RELEASE
|
||
Py_DECREF(arr1);
|
||
#endif
|
||
}
|
||
else
|
||
{
|
||
result = pythonObjectToQVariant(pResult);
|
||
QMap<QString, QVariant> imgResult = result.toMap();
|
||
emit addLog("1#executeScript" + QString::number(imgResult.size()));
|
||
}
|
||
} else {
|
||
PyErr_Print();
|
||
emit addLog("函数调用失败");
|
||
}
|
||
|
||
#ifdef _RELEASE
|
||
// 清理
|
||
Py_XDECREF(pResult);
|
||
Py_XDECREF(pArgs);
|
||
Py_XDECREF(pFunc);
|
||
Py_XDECREF(pModule);
|
||
#endif
|
||
|
||
return result;
|
||
}
|
||
|
||
/*
|
||
QVariant PythonHandler::executeScript(const QString &scriptPath,
|
||
const QString &functionName,
|
||
const QVariantList &args)
|
||
{
|
||
if (!m_initialized && !initialize()) {
|
||
return QVariant();
|
||
}
|
||
|
||
// 获取全局字典
|
||
PyObject* pModule = nullptr;
|
||
PyObject* pFunc = nullptr;
|
||
PyObject* pArgs = nullptr;
|
||
PyObject* pResult = nullptr;
|
||
QVariant result;
|
||
|
||
// 导入模块
|
||
QString moduleName = scriptPath;
|
||
if (moduleName.endsWith(".py")) {
|
||
moduleName.chop(3);
|
||
}
|
||
|
||
pModule = PyImport_ImportModule(moduleName.toStdString().c_str());
|
||
|
||
if (!pModule) {
|
||
PyErr_Print();
|
||
emit addLog("无法导入Python模块:" + moduleName);
|
||
return QVariant();
|
||
}
|
||
|
||
// 获取函数
|
||
pFunc = PyObject_GetAttrString(pModule, functionName.toStdString().c_str());
|
||
|
||
if (!pFunc || !PyCallable_Check(pFunc)) {
|
||
if (PyErr_Occurred()) {
|
||
PyErr_Print();
|
||
}
|
||
emit addLog("无法找到函数:" + functionName);
|
||
Py_XDECREF(pFunc);
|
||
Py_DECREF(pModule);
|
||
return QVariant();
|
||
}
|
||
|
||
// 构建参数
|
||
pArgs = PyTuple_New(args.size());
|
||
for (int i = 0; i < args.size(); ++i) {
|
||
PyTuple_SetItem(pArgs, i, qVariantToPythonObject(args[i]));
|
||
}
|
||
|
||
// 调用函数
|
||
pResult = PyObject_CallObject(pFunc, pArgs);
|
||
if (pResult) {
|
||
result = pythonObjectToQVariant(pResult);
|
||
QMap<QString, QVariant> imgResult = result.toMap();
|
||
emit addLog("1#executeScript" + QString::number(imgResult.size()));
|
||
} else {
|
||
PyErr_Print();
|
||
emit addLog("函数调用失败");
|
||
}
|
||
|
||
#ifdef _RELEASE
|
||
// 清理
|
||
Py_XDECREF(pResult);
|
||
Py_XDECREF(pArgs);
|
||
Py_XDECREF(pFunc);
|
||
Py_XDECREF(pModule);
|
||
#endif
|
||
|
||
return result;
|
||
}
|
||
*/
|
||
|
||
QVariant PythonHandler::executeCode(const QString &code)
|
||
{
|
||
if (!m_initialized && !initialize()) {
|
||
return QVariant();
|
||
}
|
||
|
||
PyObject* pMain = PyImport_AddModule("__main__");
|
||
PyObject* pDict = PyModule_GetDict(pMain);
|
||
|
||
PyObject* pResult = PyRun_String(code.toStdString().c_str(),
|
||
Py_eval_input,
|
||
pDict,
|
||
pDict);
|
||
|
||
if (pResult) {
|
||
QVariant result = pythonObjectToQVariant(pResult);
|
||
Py_DECREF(pResult);
|
||
return result;
|
||
} else {
|
||
PyErr_Print();
|
||
return QVariant();
|
||
}
|
||
}
|