Missing QAbstractItemModel.multiData binding
Phil Thompson
phil at riverbankcomputing.com
Wed Aug 30 13:32:16 BST 2023
If you rebuild the current PyQt6 snapshot with the next SIP snapshot
then you will get the proper iterator behaviour.
Phil
On 30/08/2023 09:37, Phil Thompson wrote:
> That's the correct code at the moment. However I've realised that it's
> very easy to add support for Python iteration.
>
> Phil
>
> On 29/08/2023 19:41, Charles wrote:
>> 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
>>>> >>
>>>>
>>>
More information about the PyQt
mailing list