Missing QAbstractItemModel.multiData binding

Charles peacech at gmail.com
Tue Aug 29 19:41:01 BST 2023


Apparently the problem is with using python iteration over the
QModelRoleDataSpan object (does it supports python iteration)?

This code instead works fine

    def multiData(self, index, roleDataSpan):
        item = self._items[index.row()]
        itemData = self._itemData(item, index.column())
        for i in range(roleDataSpan.length()):
            roleData = roleDataSpan[i]
            if roleValue := itemData.get(roleData.role()):
                roleData.setData(roleValue)
            else:
                roleData.clearData()

On Tue, Aug 29, 2023 at 8:17 PM Charles <peacech at gmail.com> wrote:

> Hi Phil, here is an example standalone code
>
> import sys
> from dataclasses import dataclass
>
> from PyQt6.QtCore import QAbstractTableModel, Qt
> from PyQt6.QtWidgets import QApplication, QMainWindow, QTableView
>
>
> @dataclass
> class Item:
>     name: str
>     weight: int
>
>
> class Model(QAbstractTableModel):
>     def __init__(self, parent=None):
>         super().__init__(parent)
>         self._items = [Item('A', 10), ('B', 11)]
>
>     def rowCount(self, index):
>         return len(self._items)
>
>     def columnCount(self, index):
>         return 2
>
>     def _itemData(self, item, column):
>         match column:
>             case 0:
>                 return {Qt.ItemDataRole.DisplayRole: item.name}
>             case 1:
>                 return {Qt.ItemDataRole.DisplayRole: str(item.weight)}
>
>     # crash
>     def multiData(self, index, roleDataSpan):
>         item = self._items[index.row()]
>         itemData = self._itemData(item, index.column())
>         for roleData in roleDataSpan:
>             if roleValue := itemData.get(roleData.role()):
>                 if existingData := roleData.data():
>                     existingData.setValue(roleValue)
>                 else:
>                     roleData.setData(roleValue)
>             else:
>                 roleData.clearData()
>
>     # works
>     # def multiData(self, index, roleDataSpan):
>     #     pass
>
>
> class Widget(QTableView):
>     def __init__(self, parent=None):
>         super().__init__(parent)
>         self.setModel(Model(self))
>
>
> class Window(QMainWindow):
>     def __init__(self):
>         super().__init__()
>         self.setCentralWidget(Widget(self))
>
>
> app = QApplication(sys.argv)
> win = Window()
> win.show()
> app.exec()
>
> On Tue, Aug 29, 2023 at 7:59 PM Phil Thompson <phil at riverbankcomputing.com>
> wrote:
>
>> Can you create a short complete example I can use?
>>
>> Thanks,
>> Phil
>>
>> On 29/08/2023 13:40, Charles wrote:
>> > I tried using multiData with this code snippet but it seems to crash
>> > when
>> > setting roleData.setData(...). Also I notice that the role values might
>> > be
>> > negative. (Btw, ic is icecream print).
>> >
>> >     def _itemData(self, item, col):
>> >         match col.name:
>> >             case 'code':
>> >                 return {
>> >                     Qt.DisplayRole: item.code,
>> >                 }
>> >             case 'earnings_chg':
>> >                 return {
>> >                     Qt.DisplayRole: f'{item.earnings_chg}%',
>> >                 }
>> >             case 'time':
>> >                 return {
>> >                     Qt.DisplayRole: item.time.strftime('%Y-%m-%d'),
>> >                 }
>> >             case 'earnings':
>> >                 return {
>> >                     Qt.DisplayRole: formatMoney(item.earnings),
>> >                 }
>> >
>> >     def multiData(self, index, roleDataSpan):
>> >         ic(index, roleDataSpan)
>> >         item = self._items[index.row()]
>> >         col = self.COLUMNS[index.column()]
>> >         itemData = self._itemData(item, col)
>> >         for roleData in roleDataSpan:
>> >             role = roleData.role()
>> >             ic(role)
>> >             if value := itemData.get(role):
>> >                 roleData.setData(value)
>> >             else:
>> >                 match role:
>> >                     case Qt.FontRole:
>> >                         roleData.setData(style.TABLE_FONT)
>> >                     case Qt.TextAlignmentRole:
>> >                         align = col.align
>> >                         if align == 'C':
>> >                             roleData.setData(Qt.AlignCenter)
>> >                         elif align == 'R':
>> >                             roleData.setData(Qt.AlignVCenter |
>> > Qt.AlignRight)
>> >
>> > ic| earnings.py:66 in multiData()
>> >     index: <PyQt6.QtCore.QModelIndex object at 0x000001D17B77D000>
>> >     roleDataSpan: <PyQt6.QtCore.QModelRoleDataSpan object at
>> > 0x000001D17B77D4D0>
>> > ic| earnings.py:72 in multiData()- role: 6
>> > ic| earnings.py:72 in multiData()- role: 7
>> > ic| earnings.py:72 in multiData()- role: 9
>> > ic| earnings.py:72 in multiData()- role: 10
>> > ic| earnings.py:72 in multiData()- role: 1
>> > ic| earnings.py:72 in multiData()- role: 0
>> > ic| earnings.py:72 in multiData()- role: 8
>> > ic| earnings.py:72 in multiData()- role: -948493808
>> > ic| earnings.py:72 in multiData()- role: 1897532384
>> > ic| earnings.py:72 in multiData()- role: 1897532384
>> > ic| earnings.py:72 in multiData()- role: 2033014364
>> > ic| earnings.py:72 in multiData()- role: 2
>> > ic| earnings.py:72 in multiData()- role: 16777216
>> > ic| earnings.py:72 in multiData()- role: 1893028080
>> > ic| earnings.py:72 in multiData()- role: 1897532384
>> > ic| earnings.py:72 in multiData()- role: 1897532384
>> > ic| earnings.py:72 in multiData()- role: 2033014458
>> > ic| earnings.py:72 in multiData()- role: 2
>> > ic| earnings.py:72 in multiData()- role: 2033021932
>> > ic| earnings.py:72 in multiData()- role: 3
>> > ic| earnings.py:72 in multiData()- role: 524288
>> > ic| earnings.py:72 in multiData()- role: 1893028080
>> > ic| earnings.py:72 in multiData()- role: 1897532384
>> > ic| earnings.py:72 in multiData()- role: 1897532384
>> > ic| earnings.py:72 in multiData()- role: 2033022038
>> > ic| earnings.py:72 in multiData()- role: 1
>> > ic| earnings.py:72 in multiData()- role: 22528
>> > ic| earnings.py:72 in multiData()- role: 1893028080
>> >
>> > On Sun, Aug 27, 2023 at 10:45 PM Phil Thompson
>> > <phil at riverbankcomputing.com>
>> > wrote:
>> >
>> >> On 14/08/2023 16:21, Jakub Fránek wrote:
>> >> > Hello
>> >> >
>> >> > I am working on a PyQt app that features a large QTableView driven
>> by a
>> >> > custom QAbstractTableModel implementation. Profiling shows that even
>> >> > after
>> >> > heavy optimization, the program spends a lot of time calling
>> >> > QAbstractItemModel.data method.
>> >> >
>> >> > I think that QAbstractItemModel.multiData method could improve the
>> >> > performance considerably, however it seems that PyQt does not support
>> >> > this
>> >> > binding (since it does not even support QModelRoleDataSpan).
>> >> >
>> >> > My question is: is there any plan of supporting
>> >> > QAbstractItemModel.multiData method in the future? If there is no
>> such
>> >> > plan
>> >> > yet, I would like to cast my vote and humbly request this binding in
>> >> > some
>> >> > future version of PyQt.
>> >>
>> >> multiData() and QModelRoleSpan are implemented in the next snapshot -
>> >> please test.
>> >>
>> >> Phil
>> >>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20230830/96b12d11/attachment.htm>


More information about the PyQt mailing list