ItemSelectionModel for custom QAstractTableModel

Viewed 50

I have this main.py with a custom QAbstractTableModel:

import sys
import signal


from PyQt6.QtGui import QGuiApplication
from PyQt6.QtQml import QQmlApplicationEngine
from PyQt6.QtCore import Qt, QAbstractTableModel


class InstalledPkgsModel(QAbstractTableModel):
    def __init__(self, data):
        super(InstalledPkgsModel, self).__init__()
        self._data = data

    def data(self, index, role):
        if role == Qt.ItemDataRole.DisplayRole:
            value = self._data[index.row()][index.column()]

            return value

    def rowCount(self, index):
        return len(self._data)

    def columnCount(self, index):
        try:
            return len(self._data[0])
        # If there are no installed mods in the prefix
        except IndexError:
            return 1


# Make app respond to Ctrl-C
signal.signal(signal.SIGINT, signal.SIG_DFL)

app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
engine.quit.connect(app.quit)  # type: ignore

# Populate manage table view installed packages
data = [
    ["git", "", "common", "1.0"],
    ["distutils", "", "common", "1.0"],
    ["bsa", "", "common", "0.4"],
    ["nexus", "", "common", "1.0"],
    ["fallout_4", "", "common", "0.1"],
]
installed_pkgs_model = InstalledPkgsModel(data)
engine.rootContext().setContextProperty("installed_pkgs_model", installed_pkgs_model)

engine.load("main.qml")

sys.exit(app.exec())

I'd like to set something up where I can select rows in the TableView that's using this model. I currently have this main.qml:

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts

ApplicationWindow {
    visible: true
    width: 1000
    height: 700
    title: "Portmod"

    TableView {
        width: 1000
        height: 700
        id: installedPkgsTable
        columnSpacing: 1
        rowSpacing: 1
        clip: true

        model: installed_pkgs_model

        selectionModel: ItemSelectionModel {
            model: installed_pkgs_model
        }

        delegate: Rectangle {
            implicitWidth: 300
            implicitHeight: 50
            color: selected ? "blue" : "lightgray"

            required property bool selected

            Text {
                text: display
            }
        } 
    }
}

The problem is, it doesn't work. Clicking on a row does nothing, and it sometimes outputs this:

qt.core.qobject.connect: QObject::disconnect: No such signal QObject::rowsAboutToBeRemoved(QModelIndex,int,int)
qt.core.qobject.connect: QObject::disconnect: No such signal QObject::columnsAboutToBeRemoved(QModelIndex,int,int)
qt.core.qobject.connect: QObject::disconnect: No such signal QObject::rowsAboutToBeInserted(QModelIndex,int,int)
qt.core.qobject.connect: QObject::disconnect: No such signal QObject::columnsAboutToBeInserted(QModelIndex,int,int)
qt.core.qobject.connect: QObject::disconnect: No such signal QObject::rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)
qt.core.qobject.connect: QObject::disconnect: No such signal QObject::columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)
qt.core.qobject.connect: QObject::disconnect: No such signal QObject::rowsMoved(QModelIndex,int,int,QModelIndex,int)
qt.core.qobject.connect: QObject::disconnect: No such signal QObject::columnsMoved(QModelIndex,int,int,QModelIndex,int)
qt.core.qobject.connect: QObject::disconnect: No such signal QObject::layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)
qt.core.qobject.connect: QObject::disconnect: No such signal QObject::layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)
qt.core.qobject.connect: QObject::disconnect: No such signal QObject::modelReset()
1 Answers

It seems like registering it via setContextProperty() has some weird behaviour. It is also not a recommended way to expose Python / C++ to QML.

Use instead:
PySide6:

QtQml.qmlRegisterSingletonInstance(
    QAbstractTableModel, "com.example.model", 1, 0, "PyModel", model
)

PyQt6:

qmlRegisterSingletonInstance(
    "com.example.model", 1, 0, "InstalledPkgsModel", installed_pkgs_model
)

Then in QML import this as per normal:

import com.example.model 1.0

And use it like this:
PySide6:

model: PyModel

PyQt6:

model: InstalledPkgsModel

Clicking on a row does nothing.

If you want to be able to select you can use SelectionRectangle

Related