Python和C++混合使用QML开发GUI

作者:糖果

pyqt和qml结合的中文资很少,在baidu上搜索,基本上就是浪费时间。在国外的blog上,有零星的几篇,但是介绍好的少。在stackoverflow上看到一篇关于pyside,发现pyside,发现pyside果然给力,那就开始我们的pyside游戏之旅吧。

【编辑器】 目前的编辑环境是,Eclipse+PyDev, Erics, QtCreator这三个工具一起使用。用前两者进PY代码编辑,用QtCreator进行QML编辑和设计。

【概要】 用PyQt,C++,QML实现一个简单但的文本输入框值得取得和设置。从编码角度来看,我们需要在Python中调用QML的function方法,并通过参数传递把python中设定的变量值给QML.需要在QML中调用Python定义的函数方法,并把QML中InputText的Text值传递给Python.无论控件和业务逻辑多复杂都是如此。

Python代码

import sys
from PySide import QtCore, QtDeclarative,  QtGui

class QtInterface(QtCore.QObject):
    signaller_in_txt = QtCore.Signal(str)
    signaller_out_txt = QtCore.Signal()
    
     def __init__(self):
        QtCore.QObject.__init__(self)
        self.in_txt = "test"
 #@的这种声明方式,会在后面的部分介绍,并且参考链接中,有一篇文也介绍的很清晰。

 #这是一个不带参数的Slot函数。                 ```python
@QtCore.Slot()
def getInputText(self):
    print self.in_txt         ```
 #这个一个带参数的Slot函数,我们就是利用这个参数,在QML中,调用这个函数,并把InputText的text值发送过来,并且在函数中,打印出这个传递值。 ```python
@QtCore.Slot(str)
def setInputText(self, text):
    print text ```
    
 #在updateValues函数中,通过信号发射,调用QML中的function函数,并将对控件的设置值,传递过去。信号变量声明,在类中,和与对应的QML函数简历毁掉联系,是在main函数中完成的。 ```python
def updateValues(self): #        self.signaller_in_txt.emit(str(self.in_txt))
    self.signaller_out_txt.emit() ```

MainView是主要View视图,继承了基类,QDeclarativeView,继承了最大化,最小话和关闭窗体的机能。

class MainView(QtDeclarative.QDeclarativeView):
    def __init__(self,  parent=None):
          #构造父类
        super( MainView,  self).__init__(parent)
          #设定窗体Title内容
        self.setWindowTitle("Counter")
          #设定与本地QML关联
        self.setSource( QtCore.QUrl.fromLocalFile('abc.qml'))
          #设定窗体尺寸变化的模式,继承了父类的模式
        self.setResizeMode( QtDeclarative.QDeclarativeView.SizeRootObjectToView)

创建一个QtGui的应用实例

qApplication = QtGui.QApplication(sys.argv)
#主视图创建
window = MainView()
#显示主视图
window.show()


#取得用于解析QML的类实例
qcontext = window.rootContext()
interface = QtInterface()
#将用户自己的QtObject子类和窗体类建立连接
qcontext.setContextProperty("qInterface",  interface)

#将信号和QML函数建立映射关联。
interface.signaller_score_a.connect(window.rootObject().updateScoreA)
interface.signaller_in_txt.connect(window.rootObject().updateInText)
interface.signaller_out_txt.connect(window.rootObject().getInTxt)

#退出应用
sys.exit(qApplication.exec_())

QML代码

QML语言基本UI元素的描述信息和功能函数,QML本身可以通过自己的函数定义执行来完成一定程度上功能,完全和背后的语言(C++,Python)脱离关系。而且在很多的平台上使用,甚至包括移动平台,可以和我的WEB服务器很好的链接,传递数据。

import QtQuick 1.1

Rectangle {
    id: rectangle1
    width: 480
    height: 272

    gradient: Gradient {
        GradientStop {
            id: gradientStop1
            position: 0
            color: "#ffffff"
        }

        GradientStop {
            position: 1
            color: "#abc09f"
        }
    }
    //UML中的函数,要通过emit发射信号调用。
    function updateInText(string) {
        in_txt.text = string
    }

    function updateIn() {
        in_txt.text = "ozzy"
    }
    //在Python中,通过emit调用getInTxt函数
    function getInTxt() {
         //console.log基本就是JavaScript的用法。
        console.log("debug")
        return (in_txt.text)
    }


    Text {
        id: score_a
        x: 150
        y: 74
        width: 131
        height: 48
        text: qsTr("Text")
        verticalAlignment: Text.AlignVCenter
        font.pixelSize: 12
    }

    MouseArea {
        id: a_scored
        x: 303
        y: 200
    }

    Rectangle {
        id: team_a
        x: 150
        y: 148
        width: 127
        height: 46
        color: "#4e3a3a"
        radius: 10

        TextInput {
            id: team_a_txt
            x: 24
            y: 13
            width: 80
            height: 20
            text: qsTr("A")
            selectionColor: "#316cc4"
            horizontalAlignment: TextInput.AlignHCenter
            font.pixelSize: 12
        }

        MouseArea {
            id: team_a_score_ma
            x: 1
            y: 0
            width: 126
            height: 46
            onClicked: {
                qInterface.aScored()
            }
        }
    }

    TextInput {
        id: in_txt
        x: 345
        y: 67
        width: 80
        height: 20
        text: qsTr("InputText")
        selectionColor: "#316cc4"
        font.pixelSize: 12

        MouseArea {
            id: in_txt_ma
            x: -17
            y: 77
            width: 115
            height: 57
            z: 2
          //直接在MouseArea中添加对应的事件处理
            onClicked: {
               //qInterface是在Python中建立的映射关系,通过这个对象实例,就可以直接调用Python中的函数方法,并且可以传递参数               
                qInterface.setInputText(in_txt.text)
     //下面的这个函数被注释掉了,因为getText()是一个C++写的方法
     //console.log(qInterface.getText())
            }
        }

    }

    Rectangle {
        id: get_in_text
        x: 322
        y: 148
        width: 127
        height: 46
        color: "#4e3a3a"
        radius: 10

        Text {
            id: text1
            x: 38
            y: 15
            width: 40
            height: 16
            text: qsTr("Enter")
            font.pixelSize: 12
        }
    }
}

C++代码

#ifndef LOGIN_H
#define LOGIN_H


#include <QObject>

class Login: public QObject
{
    Q_OBJECT
public:
     //Q_INVOKABLE关键字,可以让QML直接调用C++方法。相当于 濮阳天python中的@QtCore.Slot()
     Q_INVOKABLE QString getText(void) const;
    Login(QObject *parent = 0);
    virtual ~Login();
signals:
    void setInputText(const QString &s);
public slots: 
    void setText(const QString &s);
};
#endif // LOGIN_H

#include "login.h"
Login::Login(QObject *parent)
      :QObject(parent)
  {
    QObject::connect(this, SIGNAL(setInputText(QString)), this, SLOT(setText(QString)));
  }

    Login::~Login() {
    }

  QString LS::getText(void) const
  {
      return "from C++ Code";
  }
  void LS::setText(const QString &s) {
      qDebug("this is string.");
      qDebug("%s", s.toLocal8Bit().data());
  }

【后记】

上面的代码可以看到,PyQt和C++公用一个QML代码,QML几乎不变(不是几乎,就是一样的)。PyQT(PySide)更适应快速开发。用C++实现性能要求比较高的共同部分,则更有优势。

Python中QML调用Python函数,只要把python的函数声明为@QtCore.Slot Python调用QML函数,需要定义信号和connect QML的函数。C++是,UML调用C++函数,只要把C++函数声明过为Q_INVOKABLE。C++调用QML函数,需要声明Signal和Connect Slot函数。这点Python和C++的流程保持一致。

【参考】

  1. PytSide

  2. 在QML中使用JavaScript和Sqlite

  3. 关于QML中调用qt类中的信号,槽,成员函数,属性做记录

  4. Connecting Qt signal to QML function

  5. @符号在python中的作用

  6. Filling and reading QML UI forms from python.

糖果

糖果
LUA教程

Apache APISIX在SAE应用市场发布

Apache APISIX在SAE应用市场发布 Continue reading

APISIX后台管理路由创建接口

Published on December 06, 2019

Openresty Nginx Tengine添加动态so库

Published on October 11, 2019