Прокси-модель, содержащая на 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() и прочие?..
![We recommend hosting TIMEWEB](/media/technical_storage/timeweb-120-90.jpg)
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.Do you like it? Share on social networks!
AM
- Anna Mag
- July 17, 2024, 2:54 p.m.
C++ - Test 005. Structures and Classes
- Result:33points,
- Rating points-10
Last comments
QML - Lesson 016. SQLite database and the working with it in QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Qt Linux - Lesson 001. Autorun Qt application under Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Qt WinAPI - Lesson 007. Working with ICMP Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
Анатолий КононенкоFeb. 5, 2024, 7:50 a.m.
![EVA](/media/cache/4b/62/4b6257bdb5dfaf404a6571a1ba7910ef.webp)
EVADec. 25, 2023, 4:30 p.m.
Boost - static linking in CMake project under Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
Now discuss on the forum
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …
![BlinCT](/media/cache/ae/4a/ae4a65663ccbf14aec7b31a6df3f29a6.webp)
BlinCTJune 25, 2024, 7 a.m.
![Evgenii Legotckoi](/media/cache/5a/49/5a499b0c8eb5e79957fec0aea35e5d98.webp)
Evgenii LegotckoiJune 24, 2024, 9:11 p.m.
![BlinCT](/media/cache/ae/4a/ae4a65663ccbf14aec7b31a6df3f29a6.webp)
BlinCTMay 5, 2024, 11:46 a.m.
![Evgenii Legotckoi](/media/cache/5a/49/5a499b0c8eb5e79957fec0aea35e5d98.webp)
Evgenii LegotckoiMay 2, 2024, 8:07 p.m.
Добрый день.
Вот рабочий вариант
Вам надо было метод 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():
Полагаю, что вам придётся везде создавать соответствующий валидный индекс для дополнительного столбца, если что-то не работает