Reputation: 8067
I have a C++/Qt application which should have its GUI extensible with modules. Extending should be simple and versatile. I am just checking a concept - is it possible to have this main C++/Qt application that would execute a Python/PySide/PyQt script which would create a QWidget (or derived class) instance and embed this widget into the main C++/Qt application?
Is there any working snippet to demonstrate the feasibility of this task? I.e. how to create and embed the widget? How to pass signals between the application and the widget?
Upvotes: 11
Views: 4655
Reputation: 336
Here is adapted for QT5 version of Francois answer:
#include "Python.h"
#include <QApplication>
#include <QMainWindow>
#include <iostream>
class PythonQt
{
public:
PythonQt()
{
Py_SetProgramName(L"/path/to/executable");
Py_SetPythonHome(L"/path/to/python-home");
Py_IgnoreEnvironmentFlag = true;
Py_Initialize();
std::string code =
"import sys\n"
"print(sys.path)\n"
"from PySide2 import QtGui\n"
"from PySide2 import QtWidgets\n"
""
"all_widgets = QtWidgets.QApplication.instance().allWidgets()\n"
"window = None\n"
"for widget in all_widgets:\n"
" if str(widget.objectName()) == \"main_window\":\n"
" window = widget\n"
" break\n"
""
"def message_box():\n"
" QtWidgets.QMessageBox.information(None, 'Test', 'Hello!', \
QtWidgets.QMessageBox.Ok)\n"
" QtWidgets.QApplication.instance().quit()\n"
""
"button = QtWidgets.QPushButton('Press Me')\n"
"button.clicked.connect(message_box)\n"
"window.setCentralWidget(button)\n"
"window.move(600, 300)\n"
"window.show()";
PyRun_SimpleString(code.c_str());
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMainWindow win;
win.setObjectName("main_window");
PythonQt python_code;
a.exec();
}
Upvotes: 0
Reputation: 311
This question is a bit old, but in case someone else is face the same issue, I will try to give a useful answer.
I think it's possible. In the following example, I create a QApplication and QMainWindow in c++, embed a python interpreter, and then, on the python side, I create a QPushButton which I add to the main window.
Try this out:
#include <QApplication>
#include <QMainWindow>
#include <iostream>
#include "Python.h"
class PythonQt
{
public:
PythonQt()
{
char name[] = "test";
Py_SetProgramName(name);
Py_Initialize();
std::string code =
"from PySide import QtGui\n"
""
"all_widgets = QtGui.QApplication.instance().allWidgets()\n"
"window = None\n"
"for widget in all_widgets:\n"
" if str(widget.objectName()) == \"main_window\":\n"
" window = widget\n"
" break\n"
""
"def message_box():\n"
" QtGui.QMessageBox.information(None, 'Test', 'Hello!', \
QtGui.QMessageBox.Ok)\n"
" QtGui.QApplication.instance().quit()\n"
""
"button = QtGui.QPushButton('Press Me')\n"
"button.clicked.connect(message_box)\n"
"window.setCentralWidget(button)\n"
"window.move(600, 300)\n"
"window.show()";
PyRun_SimpleString(code.c_str());
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMainWindow win;
win.setObjectName("main_window");
PythonQt python_code;
a.exec();
}
The python script is written here in a string to have everything in a single file, but you could of course read it in from a .py file.
Object ownership could be an issue though, as shown in the link given by Trilarion.
Upvotes: 12
Reputation: 10864
I don't think this is possible. PySide/PyQt are wrappers around C++/Qt. That means you create C++ objects and Python wrapper objects and somehow the wrapper objects kind of refer to the C++ objects. This works one way as far as I know.
But you want the other way. Basically a wrapper around Python objects (which themselves are wrappers around C++ objects) to use in C++. I don't think PySide/PyQt are ready for thise. However it is possible to embed Python in other languages.
Also see How to shoot yourself in the foot. about the pitfalls of communication between C++/Qt and Python.
Upvotes: 2