将PySide/PyQt小部件嵌入Qt/C ++应用程序

10
我有一个C++/Qt应用程序,希望能够通过模块实现GUI的扩展。扩展应该是简单而多样化的。我只是在检查一个概念 - 是否可能有这个主要的C++/Qt应用程序来执行一个Python/PySide/PyQt脚本,该脚本将创建一个QWidget(或派生类)实例并将此小部件嵌入到主C++/Qt应用程序中?
是否有任何工作样例可以证明此任务的可行性?即如何创建和嵌入小部件?如何在应用程序和小部件之间传递信号?

当然,我已经搜索过了,但没有找到有用的东西。 - HiFile.app - best file manager
3个回答

10

这个问题有些陈旧,但如果还有其他人遇到了相同的问题,我会尝试给出有用的答案。

我认为这是可能的。在以下示例中,我使用c++创建了QApplication和QMainWindow,并嵌入了Python解释器,然后在Python端创建了一个QPushButton并将其添加到主窗口。

可以尝试一下:

#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();
}

这里将Python脚本写在一个字符串中,以便将所有内容放在单个文件中,但是您当然可以从.py文件中读取它。

然而,对象所有权可能是一个问题,正如Trilarion给出的链接所示。


在Debian 9(Stretch)上使用为Qt4构建的PySide,它可以完美运行。 - Jens Munk
嗨弗朗索瓦,我在qt5中运行类似的代码遇到了一些问题,你能看一下我在乔治·维诺霍多夫的回答下面的评论,并告诉我问题出在哪里吗? - undefined

2
我认为这是不可能的。PySide/PyQt 是 C++/Qt 的包装器。这意味着您创建 C++ 对象和 Python 包装器对象,一些方式下包装器对象会参考 C++ 对象。据我所知,这只能单向工作。
但您想要另一种方式。基本上,是在 C++ 中使用 Python 对象(它们本身是 C++ 对象的包装器)的包装器。我认为 PySide/PyQt 还没有准备好这样做。但是可以将 Python 嵌入其他语言
此外,请参见如何自掘坑足,了解 C++/Qt 和 Python 之间通信的陷阱。

0
这是Francois回答的适用于QT5版本的修改版:
#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();
}

嗨乔治,我在运行你的代码时遇到了一些问题。我正在使用Python 3.7和Qt 5.15。问题是,我从QtWidgets.QApplication.instance()获取的值是None,尽管我们在C++部分已经创建了一个实例。如果我在Python端创建一个QApplication实例,C++部分和Python部分将被隔离开来。我们将找不到一个名为main_window的对象。我是不是做错了什么? - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接