集成Python和QML

        Qt包括QML作为一种声明性地描述用户界面并使用JavaScript作为其中的脚本语言的手段。

        可以编写完整的独立QML应用程  序,或将它们与C ++结合使用。PyQt5允许QML以完全相同的方式与Python集成。

        特别是:

  • QObject中细分的Python类型可以使用QML注册。
  • 可以创建已注册的Python类型的实例,并使其可用于QML脚本。
  • 可以通过QML脚本创建已注册Python类型的实例。
  • 注册Python类型的Singleton实例可以由QML引擎自动创建,并可用于QML脚本。
  • QML脚本通过其属性,信号和插槽与Python对象进行交互。
  • Python属性,信号和插槽可以给出修订号,只有特定版本实现的那些才能用于QML。

注意

PyQt对QML的支持需要了解实现QML的C ++代码的内部。这可以(并且确实)在Qt版本之间发生变化,这可能意味着某些功能仅适用于特定的Qt版本,并且可能根本不适用于Qt的某些未来版本。

建议在MVC架构中,QML只应用于实现视图。模型和控制器应该用Python实现。

   注册Python类型

使用QML注册Python类型的方式与使用C ++类完成相同,即使用qmlRegisterTypeqmlRegisterSingletonType, qmlRegisterUncreatableType和 qmlRegisterRevision函数。

在C ++中,这些是基于模板的函数,它们将C ++类(有时是修订版)作为模板参数。在Python实现中,这些只是作为相应函数的第一个参数传递。

扫描二维码关注公众号,回复: 4392257 查看本文章

  一个简单的例子

以下简单示例演示了使用QML注册的Python类的实现。该类定义了两个属性。执行QML脚本,该脚本创建类的实例并设置属性的值。然后将该实例返回给Python,然后打印这些属性的值。

希望评论是自我解释的:

import sys

from PyQt5.QtCore import pyqtProperty, QCoreApplication, QObject, QUrl
from PyQt5.QtQml import qmlRegisterType, QQmlComponent, QQmlEngine


# This is the type that will be registered with QML.  It must be a
# sub-class of QObject.
class Person(QObject):
    def __init__(self, parent=None):
        super().__init__(parent)

        # Initialise the value of the properties.
        self._name = ''
        self._shoeSize = 0

    # Define the getter of the 'name' property.  The C++ type of the
    # property is QString which Python will convert to and from a string.
    @pyqtProperty('QString')
    def name(self):
        return self._name

    # Define the setter of the 'name' property.
    @name.setter
    def name(self, name):
        self._name = name

    # Define the getter of the 'shoeSize' property.  The C++ type and
    # Python type of the property is int.
    @pyqtProperty(int)
    def shoeSize(self):
        return self._shoeSize

    # Define the setter of the 'shoeSize' property.
    @shoeSize.setter
    def shoeSize(self, shoeSize):
        self._shoeSize = shoeSize


# Create the application instance.
app = QCoreApplication(sys.argv)

# Register the Python type.  Its URI is 'People', it's v1.0 and the type
# will be called 'Person' in QML.
qmlRegisterType(Person, 'People', 1, 0, 'Person')

# Create a QML engine.
engine = QQmlEngine()

# Create a component factory and load the QML script.
component = QQmlComponent(engine)
component.loadUrl(QUrl('example.qml'))

# Create an instance of the component.
person = component.create()

if person is not None:
    # Print the value of the properties.
    print("The person's name is %s." % person.name)
    print("They wear a size %d shoe." % person.shoeSize)
else:
    # Print all errors that occurred.
    for error in component.errors():
        print(error.toString())

以下example.qml是执行的QML脚本:

import People 1.0

Person {
    name: "Bob Jones"
    shoeSize: 12
}

   使用QQmlListProperty 

在Python中定义可以从QML更新的基于列表的属性是使用QQmlListProperty类完成的。但是它在Python中的使用方式与它在C ++中的使用方式略有不同。

在简单的情况下,QQmlListProperty包装一个通常是实例sttribute的Python列表,例如:

class BirthdayParty(QObject):

    def __init__(self, parent=None):
        super().__init__(parent)

        # The list which will be accessible from QML.
        self._guests = []

    @pyqtProperty(QQmlListProperty)
    def guests(self):
        return QQmlListProperty(Person, self, self._guests)

QML现在可以操作Python Person实例列表。QQmlListProperty还充当Python列表的代理,以便可以编写以下内容:

for guest in party.guests:
    print("Guest:", guest.name)

QQmlListProperty也可用于包装虚拟 列表。以下代码片段取自chapter5-listproperties.pyPyQt5附带的 示例:

class PieChart(QQuickItem):

    @pyqtProperty(QQmlListProperty)
    def slices(self):
        return QQmlListProperty(PieSlice, self,
                append=lambda pie_ch, pie_sl: pie_sl.setParentItem(pie_ch))

PieChart并且PieSlice是使用qmlRegisterType注册的快速项目 。两者的实例都可以从QML创建。 slicesPieChartQML而言,是一个属性,是一个PieSlice实例列表。

pyqtProperty装饰器指定该属性是QQmlListProperty,其名称是slices,并且该slices()函数是其getter。

getter返回QQmlListProperty的实例。这指定列表的元素应该是类型PieSlicePieChart实例(即self)具有属性,并定义将被调用以便将新元素附加到列表的可调用对象。

append调用传递两个参数:其属性将被更新(即,该对象PyChart实例),并且元件被附加(即,PieSlice实例)。在这里,我们只需将图表设置为切片的父项。请注意,实际上并没有任何列表 - 这是因为,在这个特定示例中,不需要一个列表。

append可调用的签名与相应的C ++函数的签名略有不同。在C ++中,第一个参数是QQmlListProperty实例而不是PyChart 实例。的签名atclearcount可调用都以同样的方式不同。

   使用附加属性

为了在C ++中使用附加属性,需要采取三个步骤。

  • 具有附加属性的类型必须实现一个名为的静态函数 qmlAttachedProperties。这是一个工厂,它创建要附加的属性对象的实例。
  • 具有附加属性的类型需要使用QML_DECLARE_TYPEINFOQML_HAS_ATTACHED_PROPERTIES 参数的宏来定义 。
  • 使用qmlAttachedPropertiesObject()模板函数检索附加属性对象的实例 。模板类型是具有附加属性的类型。

PyQt5使用类似但稍微简单的步骤来实现相同的功能。

有关attach.py显示附加属性使用的完整示例,请参阅PyQt5附带的示例。

   使用属性值源

属性值源在PyQt5中实现的方式与在C ++中实现的方式相同。只需从QObject和 QQmlPropertyValueSource子类, 并提供setTarget方法的实现。

   使用QQmlParserStatus 

监视QML解析器状态在PyQt5中实现的方式与在C ++中实现的方式相同。只需从QObject和 QQmlParserStatus中进行子类化, 并提供 classBegin和 componentComplete方法的实现。

   为qmlscene编写Python插件

Qt允许编写实现QML模块的插件,这些插件可以由C ++应用程序(例如qmlscene)动态加载。这些插件是QQmlExtensionPlugin的子类。PyQt5支持完全相同的东西,并允许这些插件用Python编写。换句话说,可以将用Python编写的QML扩展提供给C ++应用程序,并将用C ++编写的QML扩展提供给Python应用程序。

PyQt5提供了一个名为的QML插件pyqt5qmlplugin。这充当了实现插件的Python代码的包装。它处理Python解释器的加载,定位和导入包含QQmlExtensionPlugin实现的Python模块,创建该类的实例,并调用实例的registerTypes方法。默认情况下,pyqt5qmlplugin它安装在PyQt5Qt安装plugin目录的子目录中。

注意

pyqt5qmlplugin是QML看到的插件的名称。它的实际文件名将是不同的并且取决于操作系统。

QML扩展模块是包含名为的文件的目录qmldir。该文件包含模块的名称和实现该模块的插件的名称。它还可以指定包含插件的目录。通常这不需要,因为插件安装在同一目录中。

因此,对于调用的QML扩展模块Chartsqmldir文件的内容 可能是:

module Charts
plugin pyqt5qmlplugin /path/to/qt/plugins/PyQt5

pyqt5qmlplugin希望找到一个文件名结尾在同一个目录中的Python模块plugin.pyplugin.pyw。在这种情况下,名称chartsplugin.py将是一个明智的选择。在导入此模块之前,pyqt5qmlplugin首先将目录的名称放在开头sys.path

注意

pyqt5qmlplugin必须找到包含qmldir 文件本身的目录。它使用QML使用的相同算法来执行此操作,即它搜索由指定的一些标准位置和位置 QML2_IMPORT_PATH环境变量。使用 qmlscene时pyqt5qmlplugin不知道其-I选项指定的任何其他位置。因此, QML2_IMPORT_PATH 应始终用于指定要搜索的其他位置。

由于QML的限制,多个QML模块不可能使用相同的C ++插件。在C ++中,这不是问题,因为模块和插件之间存在一对一的关系。但是,使用Python时, pyqt5qmlplugin每个模块都使用它。有两种解决方案:

  • 在支持它的操作系统上,在包含qmldir指向实际文件的文件的目录中放置一个符号链接pyqt5qmlplugin
  • pyqt5qmlplugin在包含该qmldir 文件的目录中制作副本。

在这两种情况下,qmldir文件的内容都可以简化为:

module Charts
plugin pyqt5qmlplugin

PyQt5提供了一个可以如下运行的示例:

cd /path/to/examples/quick/tutorials/extending/chapter6-plugins
QML2_IMPORT_PATH=. /path/to/qmlscene app.qml

在Linux上,您可能还需要为其设置值 LD_LIBRARY_PATH 环境变量。

猜你喜欢

转载自blog.csdn.net/Yuyh131/article/details/84648539
QML