简体   繁体   中英

PyQt5 Dynamically add rectangles to QML grid

I have built a grid of rectangles in QML which is run from Python. engine.load('main.qml')

Window {
    id: channels
    Grid {
        columns: 2
        spacing: 9
        Rectangle {
            color: "#333"
            width: 75
            height: 75
        }
        Rectangle {
            color: "#333"
            width: 75
            height: 75
        }
    }
}

However, I would like to have over fifty rectangles, so I need to be able to dynamically create and update them from python. How can I do that?

To provide information from python (or C++) to qml we can read this link . In it recommends to use QAbstractListModel since this notifies the changes to the qml, in addition to be added dynamically we will use Repeater .

main.qml:

import QtQuick.Window 2.2
import QtQuick 2.0
import QtQuick.Controls 1.4

Window {
    visible: true
    id: channels

    Grid {
        columns: 3
        spacing: 9
        Repeater{
            model: myModel
            delegate: Rectangle{
                height: model.height
                width: model.height
                color: model.color
            }
        }
    }
}

.py:

class Data(object):
    def __init__(self, width=35, height=35, color=QColor("red")):
        self._width = width
        self._height = height
        self._color = color

    def width(self):
        return self._width

    def height(self):
        return self._height

    def color(self):
        return self._color

class Model(QAbstractListModel):

    WidthRole = Qt.UserRole + 1
    HeightRole = Qt.UserRole + 2
    ColorRole = Qt.UserRole + 3

    _roles = {WidthRole: b"width", HeightRole: b"height", ColorRole: b"color"}

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

        self._datas = []

    def addData(self, data):
        self.beginInsertRows(QModelIndex(), self.rowCount(), self.rowCount())
        self._datas.append(data)
        self.endInsertRows()

    def rowCount(self, parent=QModelIndex()):
        return len(self._datas)

    def data(self, index, role=Qt.DisplayRole):
        try:
            data = self._datas[index.row()]
        except IndexError:
            return QVariant()

        if role == self.WidthRole:
            return data.width()

        if role == self.HeightRole:
            return data.height()

        if role == self.ColorRole:
            return data.color()

        return QVariant()

    def roleNames(self):
        return self._roles

To make a test we use the following code:

main.py

if __name__ == "__main__":
    import sys
    QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
    app = QGuiApplication(sys.argv)
    engine = QQmlApplicationEngine()

    model = Model()
    model.addData(Data(44, 33, QColor("red")))
    model.addData(Data(23, 53, QColor("#333")))

    context = engine.rootContext()
    context.setContextProperty('myModel', model)

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

    if len(engine.rootObjects()) == 0:
        sys.exit(-1)

    qsrand(QTime.currentTime().msec())
    timer = QTimer(engine)
    timer.timeout.connect(lambda: model.addData(Data(20 + qrand() % 40, 
                                                     20 + qrand() % 40, 
                                                     QColor(qrand() % 255, qrand() % 255, qrand() % 255))))
    timer.start(1000)

    engine.quit.connect(app.quit)

    sys.exit(app.exec_())

The complete example you find here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM