3

I have a PySide2 Qt 5.13.1 application with a TableView. I am expereiencing some weird behavior depending on the number of rows in my table. I am trying to alternate row colors. When the number of rows is even, the stripping works as expected. When the number of rows is odd, I get a checkerboard pattern to my TableView which is not expected. The only difference between my two screenshots below is the number of rows in the model.

enter image description here

enter image description here

main.py

import sys

from PySide2.QtCore import QUrl
from PySide2.QtQml import QQmlApplicationEngine, qmlRegisterType
from PySide2.QtWidgets import QApplication

from table_model import TableModel

import qml_rc  # noqa: F401


if __name__ == "__main__":
    app = QApplication(sys.argv)

    engine = QQmlApplicationEngine()

    qmlRegisterType(TableModel, "TableModel", 1, 0, "TableModel")

    engine.load(QUrl("qrc:/main.qml"))

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

    sys.exit(app.exec_())

main.qml

import QtQuick 2.13
import QtQuick.Controls 2.13

import TableModel 1.0

ApplicationWindow {
    visible: true

    Component.onCompleted: {
        showMaximized()
    }

    width: 640
    height: 480

    TableView {
        id: tableView
        clip: true
        anchors.fill: parent
        model: TableModel {}
        topMargin: columnsHeader.implicitHeight

        columnWidthProvider: function (column) { 
            return tableView.model ? tableView.width / tableView.model.columnCount() : 0
        }

        onWidthChanged: tableView.forceLayout()

        delegate: Rectangle {
            implicitWidth: tableView.columnWidthProvider(column)
            implicitHeight: 40
            color: index % 2 == 0 ? "grey" : "lightgrey"

            Text {
                text: display
            }
        }

        Row {
            id: columnsHeader
            y: tableView.contentY
            z: 2

            Repeater {
                model: tableView.columns > 0 ? tableView.columns : 1

                Rectangle {
                    width: tableView.columnWidthProvider(modelData)
                    height: 60
                    clip: true

                    Label {
                        id: headerText
                        width: parent.width
                        horizontalAlignment: Text.AlignHCenter
                        verticalAlignment: Text.AlignVCenter
                        text: tableView.model.headerData(modelData, Qt.Horizontal)
                        elide: Text.ElideRight
                        clip: true
                    }
                }
            }
        }
    }
}

table_model.py

from typing import Any, Optional

from PySide2.QtCore import QAbstractTableModel, QModelIndex, QObject, Qt

from table import Table


class TableModel(QAbstractTableModel):
    def __init__(self, parent: QObject = None) -> None:
        super().__init__(parent)
        self._model_data = Table(
            ["This", "Is", "A", "Test", "Of", "Headers"],
            [
                ["A", 1, 2, "B", "C", "D"],
                ["E", 3, 4, "F", "G", "H"],
                ["I", 5, 6, "J", "K", "L"],
                ["M", 7, 8, "N", "O", "P"],
                ["A", 1, 2, "B", "C", "D"],
                ["E", 3, 4, "F", "G", "H"],
                ["I", 5, 6, "J", "K", "L"],
                ["M", 7, 8, "N", "O", "P"],
                ["A", 1, 2, "B", "C", "D"],
                ["E", 3, 4, "F", "G", "H"],
                ["I", 5, 6, "J", "K", "L"],
                # ["I", 5, 6, "J", "K", "L"],
            ])

    def rowCount(self, parent=QModelIndex()) -> int:
        return len(self._model_data.rows)

    def columnCount(self, parent=QModelIndex()) -> int:
        return len(self._model_data.headers)

    def data(self, index: QModelIndex, role=Qt.DisplayRole) -> Optional[Any]:
        if role != Qt.DisplayRole:
            return None

        if not self.checkIndex(index, QAbstractTableModel.CheckIndexOption.IndexIsValid):
            return None

        return self._model_data.rows[index.row()][index.column()]

    def headerData(self, section: int, orientation, role) -> Optional[str]:
        if role != Qt.DisplayRole:
            return None

        if section < 0 or section >= len(self._model_data.headers):
            return None

        return self._model_data.headers[section]

    def reset_with_data(self, model_data: Table) -> None:
        self.beginResetModel()
        self._model_data = model_data
        self.endResetModel()

table.py


from dataclasses import dataclass
from typing import Any, List


@dataclass
class Table:
    headers: List[str]
    rows: List[List[Any]]

qml.qrc

<RCC>
    <qresource prefix="/">
        <file>main.qml</file>
    </qresource>
</RCC>

Run:

pipenv run pyside2-rcc -o qml_rc.py qml.qrc
pipenv run python main.py
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
roundtheworld
  • 2,651
  • 4
  • 32
  • 51

1 Answers1

4

The index property does not represent the row number, but is:

index = row + column * total_number_of_rows

Instead use the row (ormodel.row) property:

color: model.row % 2 == 0 ? "grey" : "lightgrey"
eyllanesc
  • 235,170
  • 19
  • 170
  • 241