Missing QAbstractItemModel.multiData binding
Phil Thompson
phil at riverbankcomputing.com
Wed Aug 30 09:37:55 BST 2023
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