Reputation: 581
I am trying to extend my Qt application with python scripts plugins. It works fine if I call any not pyqt script. It works fine too if I call any pyqt script from c++ function, but I am outside a Qt Widget Application. Something like that:
#include "/usr/include/python3.5m/Python.h"
int CargaPlugins(const char* ruta, const char* nombremodulo, const char* nombrefuncion);
int main(int argc, char** argv)
{
std::string path = "PYTHONPATH=";
path.append(argv[1]);
putenv ((char*)path.c_str());
Py_Initialize();
CargaPlugins(argv[1],"plugin_loader","iniciar");
Py_Finalize();
return 0;
}
int CargaPlugins(const char* ruta, const char* nombremodulo, const char* nombrefuncion)
{
PyObject *pName, *pModule, *pDict, *pFunc;
PyObject *pArgs, *pValue;
pName = PyUnicode_DecodeFSDefault(nombremodulo);
/* Error checking of pName left out */
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL)
{
pFunc = PyObject_GetAttrString(pModule, nombrefuncion);
/* pFunc is a new reference */
if (pFunc && PyCallable_Check(pFunc))
{
pArgs = PyTuple_New(1);
pValue = PyUnicode_FromString(ruta);
if (!pValue)
{
Py_DECREF(pArgs);
Py_DECREF(pModule);
fprintf(stderr, "Cannot convert argument\n");
return 1;
}
/* pValue reference stolen here: */
PyTuple_SetItem(pArgs, 0, pValue);
pValue = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
if (pValue != NULL)
{
printf("Result of call: %ld\n", PyLong_AsLong(pValue));
Py_DECREF(pValue);
}
else
{
Py_DECREF(pFunc);
Py_DECREF(pModule);
PyErr_Print();
fprintf(stderr,"Call failed\n");
return 1;
}
}
else
{
if (PyErr_Occurred())
PyErr_Print();
fprintf(stderr, "Cannot find function \"%s\"\n", nombrefuncion);
}
Py_XDECREF(pFunc);
Py_DECREF(pModule);
}
else
{
PyErr_Print();
fprintf(stderr, "Failed to load \"%s\"\n", nombremodulo);
return 1;
}
}
And the pyqt5 module:
plugin_loader.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
import imp
import os
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from DialogoImprimir import DialogoImprimir
def iniciar(ruta):
import sys
if not hasattr(sys,'argv'):
sys.argv = []
app = QtWidgets.QApplication(sys.argv)
myapp = DialogoImprimir(getPlugins(ruta))
myapp.show()
sys.exit(app.exec_())
DialogoImprimir.py
class DialogoImprimir(QtWidgets.QDialog):
def __init__(self, datos):
QtWidgets.QDialog.__init__(self)
self.datos = datos
self.GeneraUI(datos)
-------------------
Well, my problem is that if I insert the C++ int CargaPlugins(const char* ruta, const char* nombremodulo, const char* nombrefuncion)
into my Qt Widgwets application like a function, I get this error when called:
QCoreApplication::exec: The event loop is already running
I think that the solution would be to pass a pointer of the current QApplication to python script, or if there are any way to do it, get the current QApplication when the script python is running and use it, but I don't know how could do that.
Edit:
The snippet of the code when I call the function inside Qt:
mainwindow.cpp
void MainWindow::ActionImprimir()
{
Imprimir impresor("/home/user/pathofpythonmodules/","plugin_loader","iniciar");
imprimir.cpp
Imprimir::Imprimir(const char* ruta, const char* nombremodulo, const char* nombrefuncion)
{
std::string path = "PYTHONPATH=";
path.append(ruta);
putenv ((char*)path.c_str());
Py_Initialize();
pFuncion = CargarPlugins(ruta,nombremodulo,nombrefuncion);
if (pFuncion)
{
//more things
}
}
(and CargarPlugins() is the same function that before)
Upvotes: 2
Views: 776
Reputation: 244301
Since you have a QApplication it is not necessary to create another one so the solution is:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import importlib
import os
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from DialogoImprimir import DialogoImprimir
def iniciar(ruta):
app = QtWidgets.QApplication.instance()
if app is None:
app = QtWidgets.QApplication([])
myapp = DialogoImprimir(getPlugins(ruta))
return myapp.exec_()
A complete example you find here
Upvotes: 2