PythonQt提供了一种将python脚本语言嵌入到Qt C++程序中的简单方法。
我们可以使用一种脚本语言,扩展我们的应用,Qt中对于脚本化扩展应用程序有两种方法
很多知名的软件都是用python脚本的方式,扩展自己的应用程序,下面列举一下使用该方式扩展应用的知名软件:
参考链接:
Embedding Python into Qt Applications
PythonQt主页
pythonqt源码下载
下面介绍关于PythonQt的简单使用
关于pythonqt的编译这里就不过多的介绍了,简单的说分为三个步骤:
在使用pythonqt的时候,需要先对其进行初始化,使用头文件 PythonQt.h
PythonQt::init();
如果使用封装好的Qt类型,使用如下代码初始化,使用头文件 PythonQt_QtAll.h
PythonQt_QtAll::init();
使用函数 evalScript() , 执行python代码
// 获取 __main__ python module PythonQtObjectPtr mainModule = PythonQt::self()->getMainModule(); QVariant result = mainModule.evalScript("100 + 200", Py_eval_input); qDebug() << result;
这里使用函数 PythonQt::self()->getMainModule() 获取 __main__ 模块,然后调用函数 evalScript 执行python 脚本。
使用函数 evalFile() 执行一个python脚本
PythonQtObjectPtr mainModule = PythonQt::self()->getMainModule(); mainModule.evalFile(":example.py");
执行python的函数,并传递参数
mainModule.evalScript("def addFunc(num1, num2):\n return num1 + num2"); QVariantList nums; nums << 100 << 200; result = mainModule.call("addFunc", nums); qDebug() << "Called addFunc the result is " << result;
如果编译了 PythonQt_QtAll 库,则可以直接使用Qt中提供的类,他提供了完整的QtAPI的python封装(包括C++类和QObject类的所有非槽函数、槽函数、信号、属性等等)。
包括如下模块 QtCore、QtGui、QtNetwork、QtOpenGL、QtSql、QtSvg、QtWebKit、QtXml、QtXmlPatterns、QtMultimedia、QtQml、QtQuick ,这些模块都是作为 PythonQt 的子模块使用。 对于 QtQuick 的支持还处于实验性阶段,目前不支持从python中注册新的QML组件。支持多态比如 QEvent 和多继承比如 QGraphicsTextItem 。
下面是一个实例
使用pythonQt制作如下的界面:
python中的代码如下:
from PythonQt import QtCore, QtGui # 创建Widget和布局 mainWidget = QtGui.QWidget() mainWidget.setWindowTitle('PythonWidget') mainLayout = QtGui.QVBoxLayout(mainWidget) # 创建TextEdit和一个按钮,并添加到布局 textEdit = QtGui.QTextEdit() mainLayout.addWidget(textEdit) testButton = QtGui.QPushButton('OK') mainLayout.addWidget(testButton) # 点击按钮时执行的函数 def onClicekedButton(): textEdit.append('Hello PythonQt') # 连接信号和处理函数 testButton.connect('clicked()', onClicekedButton) # 显示界面 mainWidget.resize(800, 600) mainWidget.show()
点击按钮时,文本添加字符串 Hello PythonQt
下面是使用C++的一个类:
头文件
class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); Q_INVOKABLE void setTextEditText(const QString& text); private: QTextEdit* m_pTextEdit = nullptr; };
cpp文件
Widget::Widget(QWidget *parent) : QWidget(parent) { QVBoxLayout* mainLayout = new QVBoxLayout(this); m_pTextEdit = new QTextEdit; m_pTextEdit->setObjectName("TestTextEdit"); mainLayout->addWidget(m_pTextEdit); } Widget::~Widget() { } void Widget::setTextEditText(const QString& text) { m_pTextEdit->setText(text); }
使用函数 addObject() 添加一个对象到python环境中:
调用如下:
Widget w; w.show(); // 添加一个对象 mainModule.addObject("testWidget", &w); // 添加终端 PythonQtScriptingConsole console(nullptr, mainModule); console.show();
这里使用了 PythonQtScriptingConsole 类创建了一个python终端窗口。 可以直接在终端中调用添加的对象的函数,这里可以调用槽函数、使用 Q_INVOKABLE 修饰的函数、属性、信号等。
同时也可以通过objectname定位到子控件:
PythonQt提供了一种通用的方法,来实现不论继承QObject的类还是普通的C++类来封装类提供给python环境。
如果想要在python中调用C++的类,只需如下三个步骤:
通过继承QObject实现包装器,并以特定的命名完成构造等函数的实现。
下面是一个普通的类定义:
// 测试普通类 class NormalClass { public: NormalClass(){ qDebug() << __FUNCTION__; } ~NormalClass(){ qDebug() << __FUNCTION__; } QString m_sTestName = ""; };
对于没有继承自 QObject 的类,还需要加上如下代码
// register it to the meta type system Q_DECLARE_METATYPE(NormalClass)
下面是装饰器的定义
class NormalClassWrapper : public QObject { Q_OBJECT public slots: // Normal Class NormalClass* new_NormalClass(){ return new NormalClass; } void delete_NormalClass(NormalClass* o){ delete o; } void setTestName(NormalClass* o, const QString& name){ o->m_sTestName = name; } QString getTestName(NormalClass* o) { return o->m_sTestName; } // Widget Widget* new_Widget(QWidget* parent = nullptr){return new Widget(parent);} void delete_Widget(Widget* o){ delete o; } };
这里的 Widget 是之前定义的那个 Widget 。
下面是注册代码:
// 注册普通类 PythonQt::self()->registerCPPClass("NormalClass", "", \ "example", PythonQtCreateObject<NormalClassWrapper>); // 注册继承自QObject的类 PythonQt::self()->registerClass(&Widget::staticMetaObject, \ "example", PythonQtCreateObject<NormalClassWrapper>);
测试python脚本
from PythonQt import * normalObj = example.NormalClass() normalObj.setTestName('不会飞的纸飞机') w = example.Widget() w.setTextEditText(normalObj.getTestName()) w.show()
预览: