QSortFilterProxyModel по значению столбца - PullRequest
0 голосов
/ 15 ноября 2018

Пример данных модели таблицы

У меня есть графический интерфейс с tabWidget, и внутри каждого из них есть таблица. Каждая вкладка описывает папку (см. Тип столбца) с подкаталогами, из которых я извлекаю данные. Я хочу иметь одну основную модель, которая управляет всеми представлениями, присоединяя модель QSortFilterProxy между каждым табличным представлением, которое фильтрует основную модель для «типа» каждого отдельного табличного представления (переданного в подкласс RenderTypeProxyModel). Бонус: в идеале, они также должны быть отсортированы, так что самый последний вид (см. Столбец даты) выходит на первое место. Вот моя текущая версия, но таблица остается пустой по причине, которую я не могу понять:

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_())

Вот пример данных для отладки: https://pastebin.com/AB1XvKju Просто введите его в переменную exportData внутри метода __main__.

1 Ответ

0 голосов
/ 15 ноября 2018

Ошибка вызвана тем, что type является зарезервированным словом в python:

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

, вы должны использовать self.__type.

С другой стороны, если вы хотите отсортировать данные подата, когда нет необходимости включать setSortingEnabled(), просто используйте 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_())

Обновление:

В следующей части я улучшил ваш исходный код, избегая перезаписи ненужных методов и добавляя делегата:

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_())
...