【问题标题】:manage QML Repeater from python从 python 管理 QML 中继器
【发布时间】:2021-03-03 11:16:45
【问题描述】:

我一直在尝试制作 10 个不同的元素,例如按钮,我可以使用中继器来做到这一点,但我在为每个新元素设置文本时遇到了麻烦。

我正在从 Python 列表中获取我想要设置的文本,并通过QStringListModel 将它们发送到 qml。文本按照我的意愿从列表中获取到 qml,但不知何故,中继器集是所有元素的文本,作为 Python 给出的列表中的最后一个字符串。

稍后我将提供代码以获得额外的解释,但现在我想看看是否有人知道我该怎么做......(问题是代码在另一个设备中,我正在等待它) .基本上我想做的是,例如,我在 python a_list = {buttonName, buttonAge, buttonHeight} 中有一个列表,我想在 qml 中创建多个按钮作为列表的大小(在本例中为 3)并更改每个我在中继器中制作的按钮的文本作为列表中的字符串)。

这是 main.py

import sys
from PySide2.QtCore import QUrl
from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine

from foo import FooController

if __name__ == '__main__':
    app = QGuiApplication(sys.argv)
    engine = QQmlApplicationEngine()
    fooController = FooController()
    engine.rootContext().setContextProperty("fooController", fooController)

    engine.load(QUrl.fromLocalFile('main.qml'))

    if not engine.rootObjects():
        sys.exit(-1)
    sys.exit(app.exec_())

这是 foo.py

from PySide2.QtCore import QObject, Property, Slot

class x:
    def __init__(self, name, age):
        self.name = name
        self.age = age

class FooController(QObject):
    def __init__(self, parent=None):
        QObject.__init__(self, parent)

        self.__text = "Foo"
        self.__name = s1.name
        self.__age = s1.age

    @Property(str)
    def text(self):
        return self.__name

    @Slot()
    def clickListener(self):
        print(self.__name)

这是 foo.qml

import QtQuick 2.9
import QtQuick.Controls 2.2
Button {
    text: fooController.text
    onClicked: fooController.clickListener()
}

这是包含中继器的 qml 窗口

import QtQuick 2.0
import "../components"
//import QtQuick.Timeline 1.0
import QtQuick.Controls 2.15

import QtQuick 2.15
import QtQuick.Window 2.15
import QtGraphicalEffects 1.15
import QtQuick.Layouts 1.15
import "../main.py"

window{
    width: 1500
    height: 920
    minimumWidth: 1100
    minimumHeight: 650
    visible: true
    color: "#00000000"
    id: mainWindow
    title: qsTr("--")
    Rectangle{
            id: rectangle
            anchors.fill: parent
            anchors.rightMargin: 0
            anchors.bottomMargin: 0
            anchors.leftMargin: 0
            anchors.topMargin: 0
            radius: 10
            color: "#4642b6"
            Flickable {
                id: flickable
                contentHeight: gridLayoutBottom.height
                anchors.left: parent.left
                anchors.right: parent.right
                anchors.top: parent.top
                anchors.bottom: parent.bottom
                anchors.topMargin: 96
                anchors.rightMargin: 8
                anchors.leftMargin: 8
                anchors.bottomMargin: 8
                clip: true
                ListModel {
                            id: imageModel

                            ListElement { _id: "tile0" }


                        }
                Repeater {
                        model: imageModel
                        delegate: CustomMenuType{
                            ListView{
                                model: s

                                delegate: Text {
                                    text: model.display
                                    font.family: "Segoe UI"
                                    color: "#ffffff"
                                }
                            }

                            //text: ListView.delegate.Text.text
                            font.pointSize: 9
                            Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter

                        }
               }
            }
    }
}

【问题讨论】:

    标签: python qml pyside2


    【解决方案1】:

    免责声明:您提供的代码毫无用处,因为它没有显示任何解决您的问题的尝试,此外还有未定义的元素,我不会将其作为我的答案的基础,这是一种耻辱,因为您总是通过纠正错误来了解更多信息。

    如果您想处理中继器从 Python 中使用的信息,那么您必须使用模型。中继器支持 3 种类型的模型:

    • 一个数字,
    • 列表或
    • 继承自 QAbstractItemModel 的对象。

    在这种情况下,第一个不提供重要信息,因为它只指示元素的数量,所以它不会显示它,因为它是一个微不足道的例子。

    在列表的情况下,逻辑是创建一个类型为“QVariantList”的 Q_PROPERTY(在 PyQt5 中列表就足够了),并且每次列表更改时都会发出一个关联信号,以便通知和更新视图这幅画。

    import os.path
    import sys
    
    from PySide2.QtCore import Property, QObject, QDateTime, QTimer, QUrl, Signal
    from PySide2.QtGui import QGuiApplication
    from PySide2.QtQml import QQmlApplicationEngine
    
    
    CURRENT_DIRECTORY = os.path.dirname(os.path.realpath(__file__))
    
    
    class Controller(QObject):
        modelChanged = Signal()
    
        def __init__(self, parent=None):
            super().__init__(parent)
    
            self._model = ["Text1", "Text2", "Text3"]
    
        @Property("QVariantList", notify=modelChanged)
        def model(self):
            return self._model
    
        def update_model(self, l):
            self._model = l[:]
            self.modelChanged.emit()
    
    
    if __name__ == "__main__":
        app = QGuiApplication(sys.argv)
    
        controller = Controller()
    
        engine = QQmlApplicationEngine()
        engine.rootContext().setContextProperty("controller", controller)
        filename = os.path.join(CURRENT_DIRECTORY, "main.qml")
        engine.load(QUrl.fromLocalFile(filename))
    
        if not engine.rootObjects():
            sys.exit(-1)
    
        def on_timeout():
            dt = QDateTime.currentDateTime()
            l = [dt.addSecs(i).toString() for i in range(3)]
            controller.update_model(l)
    
        timer = QTimer(timeout=on_timeout, interval=1000)
        timer.start()
    
        sys.exit(app.exec_())
    
    import QtQuick 2.15
    import QtQuick.Window 2.15
    import QtQuick.Controls 2.15
    
    Window{
        width: 640
        height: 480
        visible: true
    
        Column {
            Repeater {
                model: controller.model
                Button {
                    text: model.modelData
                }
            }
        }
    }
    

    在 QAbstractItemModel 的情况下,逻辑是创建 QObject 类型的 QProperty 并使其保持不变,因为模型本身不会改变,但它管理的信息会改变。而在 QML 方面,必须使用关联的角色访问属性,例如在 QStringListModel 的情况下,角色是“显示”:

    import os.path
    import sys
    
    from PySide2.QtCore import Property, QDateTime, QObject, QStringListModel, QTimer, QUrl
    from PySide2.QtGui import QGuiApplication
    from PySide2.QtQml import QQmlApplicationEngine
    
    
    CURRENT_DIRECTORY = os.path.dirname(os.path.realpath(__file__))
    
    
    class Controller(QObject):
        def __init__(self, parent=None):
            super().__init__(parent)
    
            self._model = QStringListModel()
    
            self.model.setStringList(["Text1", "Text2", "Text3"])
    
        def get_model(self):
            return self._model
    
        model = Property(QObject, fget=get_model, constant=True)
    
    
    if __name__ == "__main__":
        app = QGuiApplication(sys.argv)
    
        controller = Controller()
    
        engine = QQmlApplicationEngine()
        engine.rootContext().setContextProperty("controller", controller)
        filename = os.path.join(CURRENT_DIRECTORY, "main.qml")
        engine.load(QUrl.fromLocalFile(filename))
    
        if not engine.rootObjects():
            sys.exit(-1)
    
        def on_timeout():
            dt = QDateTime.currentDateTime()
            l = [dt.addSecs(i).toString() for i in range(3)]
            controller.model.setStringList(l)
    
        timer = QTimer(timeout=on_timeout, interval=1000)
        timer.start()
    
        sys.exit(app.exec_())
    
    import QtQuick 2.15
    import QtQuick.Window 2.15
    import QtQuick.Controls 2.15
    
    Window{
        width: 640
        height: 480
        visible: true
    
        Column {
            Repeater {
                model: controller.model
                Button {
                    text: model.display
                }
            }
        }
    }
    

    您也可以创建自定义模型,但必须声明与数据关联的角色,一个简单的示例是使用 QStandardItemModel 类。

    import os.path
    import sys
    
    from PySide2.QtCore import (
        Property,
        QDateTime,
        QObject,
        Qt,
        QTimer,
        QUrl,
    )
    from PySide2.QtGui import QGuiApplication, QStandardItem, QStandardItemModel
    from PySide2.QtQml import QQmlApplicationEngine
    
    
    CURRENT_DIRECTORY = os.path.dirname(os.path.realpath(__file__))
    
    TEXT_ROLE = Qt.UserRole + 1000
    DATA_ROLE = TEXT_ROLE + 1
    
    
    class Controller(QObject):
        def __init__(self, parent=None):
            super().__init__(parent)
    
            self._model = QStandardItemModel()
            self.model.setItemRoleNames({TEXT_ROLE: b"text", DATA_ROLE: b"data"})
            for i in range(3):
                item = QStandardItem()
                item.setData("Text{}".format(i), TEXT_ROLE)
                item.setData(i, DATA_ROLE)
                self.model.appendRow(item)
    
        def get_model(self):
            return self._model
    
        model = Property(QObject, fget=get_model, constant=True)
    
    
    if __name__ == "__main__":
        app = QGuiApplication(sys.argv)
    
        controller = Controller()
    
        engine = QQmlApplicationEngine()
        engine.rootContext().setContextProperty("controller", controller)
        filename = os.path.join(CURRENT_DIRECTORY, "main.qml")
        engine.load(QUrl.fromLocalFile(filename))
    
        if not engine.rootObjects():
            sys.exit(-1)
    
        def on_timeout():
            dt = QDateTime.currentDateTime()
            for i in range(controller.model.rowCount()):
                item = controller.model.item(i)
                item.setData(dt.addSecs(i).toString(), TEXT_ROLE)
                item.setData(dt.addSecs(i), DATA_ROLE)
    
        timer = QTimer(timeout=on_timeout, interval=1000)
        timer.start()
    
        sys.exit(app.exec_())
    
    import QtQuick 2.15
    import QtQuick.Window 2.15
    import QtQuick.Controls 2.15
    
    Window{
        width: 640
        height: 480
        visible: true
    
        Column {
            Repeater {
                model: controller.model
                Button {
                    text: model.text
                    onClicked: console.log(model.data)
                }
            }
        }
    }
    

    您还可以创建一个继承自 QAbstractListModel 并覆盖数据、setData、roleNames、rowCount 方法的类。

    【讨论】:

      猜你喜欢
      • 2021-05-22
      • 1970-01-01
      • 1970-01-01
      • 2013-03-27
      • 2019-08-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多