jnt
jnt

Reputation: 39

QSortFilterProxyModel by column value

Example of table model data

I have a gui with a tabWidget and inside each I have a tableview. Each tab describes a folder (see column type) with subdirs from which I pull the data. I want to have one main model that drives all views by attaching a QSortFilterProxy Model inbetween each tableview that filters the main model for the "type" of each individual TableView (passed into the subclass RenderTypeProxyModel). Bonus: Ideally, they should be sorted as well, so that the most recent view (see date column) comes out on top. Here is my current version but the table remains blank for a reason I can't figure out:

import sys
import os
from datetime import datetime
from pprint import pprint
from PySide2 import QtCore, QtGui, QtWidgets

#To be replaced by env variable
pathToProject = "/run/media/centos7/Data/Projects/Programming/Pipeline/SampleProject"
allowedExportTypes = ["img-prv", "img-final", "img-cg", "img-src", "camera"]


class ExportTableModel(QtCore.QAbstractTableModel):
    def __init__(self, exportData, horizontalHeaders, parent=None):
        QtCore.QAbstractTableModel.__init__(self, parent)
        self.__exportData = exportData
        self.__horizontalHeaders = horizontalHeaders

    def rowCount(self, parent):
        return len(self.__exportData)
    def columnCount(self, parent):
        return len(self.__horizontalHeaders)

    def data(self, index, role): #Returns the data stored under the given role for the item referred to by the index.
        if role == QtCore.Qt.DisplayRole:
            row = index.row()
            column = index.column()
            value = self.__exportData[row][column]
            return value

    def headerData(self, section, orientation, role):
        if role == QtCore.Qt.DisplayRole:
            if orientation == QtCore.Qt.Horizontal:
                if section < len(self.__horizontalHeaders):
                    return self.__horizontalHeaders[section]
                else:
                    return "not implemented"

def tableSetup(tableView):
    tableView.setAlternatingRowColors(True)
    tableView.setSelectionBehavior(QtWidgets.QTableView.SelectRows)
    tableView.setSortingEnabled(True)

class RenderTypeProxyModel (QtCore.QSortFilterProxyModel): #Custom Proxy Model
    def __init__(self, type, parent=None):
        super(RenderTypeProxyModel,self).__init__(parent)
        self.__type = type

    def filterAcceptsRow(self, row, parent): #returns true if the given row should be included in the model
        model = self.sourceModel()
        index = model.index(row, 3, parent)
        if model.data(index,QtCore.Qt.DisplayRole) == type:
            return True
        else:
            return False

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

    horizontalHeaders = ["status", "comment", "task", "type", "version", "user", "date", "filepath"] #horizontal header data
    #exportData = #insert sample data list of lists here for testing

    tableView = QtWidgets.QTableView()
    tableView.show()

    model = ExportTableModel(exportData,horizontalHeaders)
    proxyModel = RenderTypeProxyModel("img-prv")
    proxyModel.setSourceModel(model)
    tableView.setModel(proxyModel)

    tableSetup(tableView)
    sys.exit(app.exec_())

Here is sample data to use for debugging: https://pastebin.com/AB1XvKju Just feed it into the exportData variable inside the __main__ method.

Upvotes: 1

Views: 4492

Answers (1)

eyllanesc
eyllanesc

Reputation: 244291

The error is caused because type is a reserved word in python:

if model.data(index,QtCore.Qt.DisplayRole) == type:

you must use self.__type.

On the other hand if you want to sort the data by date it is not necessary to enable setSortingEnabled(), just use sort().

from PySide2 import QtCore, QtGui, QtWidgets

#To be replaced by env variable
allowedExportTypes = ["img-prv", "img-final", "img-cg", "img-src", "camera"]


class ExportTableModel(QtCore.QAbstractTableModel):
    def __init__(self, exportData, horizontalHeaders, parent=None):
        super(ExportTableModel, self).__init__(parent)
        self.__exportData = exportData
        self.__horizontalHeaders = horizontalHeaders

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

    def columnCount(self, parent=QtCore.QModelIndex()):
        return len(self.__horizontalHeaders)

    def data(self, index, role=QtCore.Qt.DisplayRole):
        if role == QtCore.Qt.DisplayRole:
            row = index.row()
            column = index.column()
            value = self.__exportData[row][column]
            return value

    def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
        if role == QtCore.Qt.DisplayRole and orientation == QtCore.Qt.Horizontal:
            if section < self.columnCount():
                return self.__horizontalHeaders[section]
            return "not implemented"

def tableSetup(tableView):
    tableView.setAlternatingRowColors(True)
    tableView.setSelectionBehavior(QtWidgets.QTableView.SelectRows)

class RenderTypeProxyModel (QtCore.QSortFilterProxyModel): #Custom Proxy Model
    def __init__(self, _type, parent=None):
        super(RenderTypeProxyModel,self).__init__(parent)
        self.__type = _type

    def filterAcceptsRow(self, row, parent):
        _type = self.sourceModel().index(row, 3, parent).data()
        return _type == self.__type

    def lessThan(self, left, right):
        fmt = "yyyy-MM-dd hh:mm:ss"
        left_data = self.sourceModel().data(left)
        right_data = self.sourceModel().data(right)
        return QtCore.QDateTime.fromString(left_data, fmt) < QtCore.QDateTime.fromString(right_data, fmt)

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)

    horizontalHeaders = ["status", "comment", "task", "type", "version", "user", "date", "filepath"] #horizontal header data
    exportData = # ...
    model = ExportTableModel(exportData, horizontalHeaders)
    tab_widget = QtWidgets.QTabWidget()
    for _type in allowedExportTypes:
        tableView = QtWidgets.QTableView()
        c = horizontalHeaders.index("date")
        tableSetup(tableView)
        proxy = RenderTypeProxyModel(_type, tableView)
        proxy.setSourceModel(model)
        proxy.sort(c, QtCore.Qt.AscendingOrder)
        tableView.setModel(proxy)
        tab_widget.addTab(tableView ,_type)

    tab_widget.show()
    sys.exit(app.exec_())

Update:

In the next part I have made improvements to your original code avoiding overwriting unnecessary methods and adding a delegate:

from PySide2 import QtCore, QtGui, QtWidgets

#To be replaced by env variable
allowedExportTypes = ["img-prv", "img-final", "img-cg", "img-src", "camera"]


class DateDelegate(QtWidgets.QStyledItemDelegate):
    def initStyleOption(self, option, index):
        super(DateDelegate, self).initStyleOption(option, index)
        option.text = index.data().toString("yyyy-MM-dd hh:mm:ss")

class ExportTableModel(QtCore.QAbstractTableModel):
    def __init__(self, exportData, horizontalHeaders, parent=None):
        super(ExportTableModel, self).__init__(parent)
        self.__exportData = exportData
        self.__horizontalHeaders = horizontalHeaders

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

    def columnCount(self, parent=QtCore.QModelIndex()):
        return len(self.__horizontalHeaders)

    def data(self, index, role=QtCore.Qt.DisplayRole):
        if role == QtCore.Qt.DisplayRole:
            row = index.row()
            column = index.column()
            value = self.__exportData[row][column]
            header = self.headerData(column, QtCore.Qt.Horizontal)
            if header == "date":
                value = QtCore.QDateTime.fromString(value, "yyyy-MM-dd hh:mm:ss")
            return value

    def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
        if role == QtCore.Qt.DisplayRole and orientation == QtCore.Qt.Horizontal:
            if section < self.columnCount():
                return self.__horizontalHeaders[section]
            return "not implemented"

def create_tableview():
    tableView = QtWidgets.QTableView()
    tableView.setAlternatingRowColors(True)
    tableView.setSelectionBehavior(QtWidgets.QTableView.SelectRows)
    return tableView

class RenderTypeProxyModel (QtCore.QSortFilterProxyModel):
    def __init__(self, c_type, _type, c_date, model, parent=None):
        super(RenderTypeProxyModel,self).__init__(parent)
        self.setSourceModel(model)
        self.setFilterKeyColumn(c_type)
        self.setFilterFixedString(_type)
        self.sort(c_date, QtCore.Qt.AscendingOrder)


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)

    horizontalHeaders = ["status", "comment", "task", "type", "version", "user", "date", "filepath"] #horizontal header data
    exportData = # ...
    c_date = horizontalHeaders.index("date")
    c_type = horizontalHeaders.index("type")
    tab_widget = QtWidgets.QTabWidget()
    for _type in allowedExportTypes:
        tableView = create_tableview()
        tab_widget.addTab(tableView ,_type)
        proxy = RenderTypeProxyModel(c_type, _type, c_date, model, tableView)
        tableView.setModel(proxy)
        delegate = DateDelegate(tableView)
        tableView.setItemDelegateForColumn(c_date, delegate)

    tab_widget.show()
    sys.exit(app.exec_())

Upvotes: 2

Related Questions