Прокси-модель, содержащая на 1 столбец больше, чем модель-источник.
qt5, model, proxy, QIdentityProxyModel, column, PyQt5
Здравствуйте!
Пытаюсь переопределить QIdentityProxyModel так, чтобы она имела на 1 столбец больше, чем ее модель-источник, но никак не могу добиться успешного результата.
Вот заготовка, очищенная от мусора:
#!/usr/bin/python3 # -*- coding: utf-8 -*- """Попытка реализовать прокси-модель, содержащую на 1 столбец больше, чем модель-источник.""" import sys import typing from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * app = None class MyProxyModel(QIdentityProxyModel): """Прокси-модель, содержащая на 1 столбец больше, чем модель-источник.""" VALUE = "===" def columnCount(self, parent: QModelIndex = None) -> int: """Переопределяет соответствующий родительский метод. columnCount(self, parent: QModelIndex = QModelIndex()) -> int """ if not self.sourceModel(): return 0 return super().columnCount() + 1 def data(self, proxyIndex: QModelIndex, role: int = None) -> typing.Any: """Переопределяет соответствующий родительский метод. data(self, index: QModelIndex, role: int = Qt.DisplayRole) -> Any """ assert self.checkIndex(proxyIndex) if role is None: role = Qt.DisplayRole if not self.sourceModel(): return None if role == Qt.DisplayRole: if proxyIndex.column() == self.columnCount() - 1: # text = "" # for column in range(self.columnCount() - 1): # # index = self.index(proxyIndex.row(), column, proxyIndex.parent()) # index = self.sibling(proxyIndex.row(), column, proxyIndex) # text += "->" + str(super().data(index)) # return text return self.VALUE return super().data(proxyIndex, role) def headerData(self, section: int, orientation: int, role: int = None) -> typing.Any: """Переопределяет соответствующий родительский метод. headerData(self, section: int, orientation: Qt.Orientation, role: int = Qt.DisplayRole) -> Any """ if role is None: role = Qt.DisplayRole if orientation == Qt.Horizontal and role == Qt.DisplayRole and section == self.columnCount() - 1: return "New column" return super().headerData(section, orientation, role) # def mapFromSource(self, sourceIndex: QModelIndex) -> QModelIndex: # # return super().mapFromSource(sourceIndex) # if not self.sourceModel() or not sourceIndex.isValid(): # return QModelIndex() # # assert sourceIndex.model() is self.sourceModel() # return self.createIndex(sourceIndex.row(), sourceIndex.column(), sourceIndex.internalPointer()) # # def mapToSource(self, proxyIndex: QModelIndex) -> QModelIndex: # # return super().mapToSource(proxyIndex) # if not self.sourceModel() or not proxyIndex.isValid(): # return QModelIndex() # # assert proxyIndex.model() is self # return self.sourceModel().createIndex(proxyIndex.row(), proxyIndex.column(), proxyIndex.internalPointer()) def main(): global app app = QApplication(sys.argv) sourceModel = QFileSystemModel(app) sourceModel.setRootPath(".") proxyModel = MyProxyModel(app) proxyModel.setSourceModel(sourceModel) treeView = QTreeView() treeView.setMinimumWidth(800) treeView.setModel(proxyModel) treeView.setColumnWidth(0, 400) # TODO: По прежнему выделяет только ячейку. Надо переопределить MyProxyModel.mapSelection<From/To>Source()! treeView.setSelectionBehavior(treeView.SelectRows) # treeView.setSelectionMode(treeView.SingleSelection) treeView.show() def checkProxyModel(): print("BEGIN checkProxyModel()") assert proxyModel.columnCount() == sourceModel.columnCount() + 1 proxyIndexWithZeroColumn = proxyModel.index(0, 0) sourceIndexWithZeroColumn = sourceModel.index(0, 0) assert proxyModel.data(proxyIndexWithZeroColumn) == sourceModel.data(sourceIndexWithZeroColumn) proxyIndexWithPenultimateColumn = proxyModel.index(0, proxyModel.columnCount() - 2) sourceIndexWithLastColumn = sourceModel.index(0, sourceModel.columnCount() - 1) assert proxyModel.data(proxyIndexWithPenultimateColumn) == sourceModel.data(sourceIndexWithLastColumn) proxyIndexWithLastColumn = proxyModel.index(0, proxyModel.columnCount() - 1) assert proxyModel.data(proxyIndexWithLastColumn, Qt.DisplayRole) == proxyModel.VALUE print("END checkProxyModel()") QTimer.singleShot(0, checkProxyModel) sys.exit(app.exec()) if __name__ == '__main__': main()
В отображении появляется новый столбец с нужным заголовком, но без данных.
Я не понимаю, каким образом мне нужно переопределить методы mapFromSource/mapToSource, чтоб все заработало...
Или же вообще нужно переопределять index(), parent() и прочие?..
Рекомендуємо хостинг TIMEWEB
Стабільний хостинг, на якому розміщується соціальна мережа EVILEG. Для проектів на Django радимо VDS хостинг.Вам це подобається? Поділіться в соціальних мережах!
- Akiv Doros
- 12 листопада 2024 р. 01:58
C++ - Тест 004. Указатели, Массивы и Циклы
- Результат:50бали,
- Рейтинг балів-4
- molni99
- 26 жовтня 2024 р. 11:37
C++ - Тест 004. Указатели, Массивы и Циклы
- Результат:80бали,
- Рейтинг балів4
- molni99
- 26 жовтня 2024 р. 11:29
C++ - Тест 004. Указатели, Массивы и Циклы
- Результат:20бали,
- Рейтинг балів-10
Добрый день.
Вот рабочий вариант
Вам надо было метод index переопределить, чтобы создавался QModelIndex для вашей спец-колонки
Огромное спасибо за ответ!:)
Но вариант все же не является рабочим.
Почти всегда дерево отображается корректно и даже раскрываются новые уровни, если нажать точно на треугольник слева. Но если сменить выделенный элемент, например, щелкнуть мышкой на какую-нибудь ячейку, то приложение падает, и единственным выводом в консоль является:
qVersion() == 5.11.1, OS == Kubuntu 18.04
Также приложение падает, если вернуть в метод data() строчку
Изучение исходников метода index() в QFileSystemModel и QStandardItemModel ничем пока не помогло. :(
Падение с assert - это уже питоновские заморочки, дайте туда более корректную проверку, поскольку проверка на None просто не работает адекватно в том случае.
Что касается установки информации, то возможно, что ещё потребуется перепределить метод setData. Переопределите его и посмотрите через print, что туда прилетает в индексе и роли.
До setData() я еще не добрался, так как пока что даже reed only модель не работает.
В конкретном данном случае в
всегда передается экземпляр QModelIndex. Поэтому это не является проблемой обработки None.
Да и на падения при смене текущей ячейки это не влияет.
Я Вам очень благодарен за то, что все равно пытаетесь помочь!
Если определить метод index() таким костыльным и затратным образом:
то приложение уже перестает падать, но строку вьюха выделить все еще не может, так как для модельного индекса из моего столбца internalPointer() хранит данные, отличающиеся от данных для других столбцов.
Также в этом случае в консоль выводится соответствующее сообщение:
Can't select indexes from different model or with different parents
В итоге, эмулировать существование дополнительных столбцов через QIdentityModel на PyQt5(5.11.1) получается только для плоских (табличных, списочных) моделей.
Для древовидных моделей при создании модельного индекса в internalPointer необходимо хранить некие данные о родителе. Но если установить в него данные можно, то при считывании PyQt не может определить их тип из-за того, что в С++ они объявлены как void*, если считывать через internalPointer(), и qintptr, если считывать через internalId().
В следствие чего, программа крашится.
Попробуйте ещё PySide 2 - это официально поддерживаемый пакет привязок Python к Qt, возможно, что там не будет таких проблем.
Вот работающий вариант переопределения метода index():
Теперь корректно устанавливаются дынные об элементе-предке и программа больше не крашится.
Но остается вопрос, как заставить вьюху менять выделение/текущий индекс при щелчке мышкой по ячейкам из нового столбца?..
Изучение исходников QTreeView и QAbstractItemView показало, что для осуществления обработки нажатий по элементам нового столбца необходимо переопределить метод sibling():
Полагаю, что вам придётся везде создавать соответствующий валидный индекс для дополнительного столбца, если что-то не работает