Могу ли я ускорить оптимизацию использования GridCellAttr в wx.grid.Grid wxPython?
Я делаю приложение для Windows, используя wx.grid.Grid
это будет обрабатывать очень большие документы Microsoft Excel. В настоящее время он довольно быстро открывает файл с 17 столбцами и более 12 000 строк, и я могу плавно перемещаться. (Это виртуальная таблица, которая работает с данными из пользовательского класса таблицы.)
В любом случае, проблема начинается, когда я использую пользовательские объекты атрибутов ячейки сетки, например:
grid.SetAttr(row, col, SomeGridCellAttr('#FF0000'))
Как только каждая ячейка в строке имеет собственный атрибут ячейки сетки, производительность сетки просто уходит на 99,9% в унитаз. Вместо плавной прокрутки мне повезло, если я получаю 1 перерисовку за 3 секунды. Я исправил большинство этих случаев с помощью grid.SetColAttr
вместо этого это восстановило производительность до прежнего уровня, но есть один случай, когда это не сработает. Приложение выполняет итерацию по каждой ячейке в столбце (12 000 ячеек), выполняет некоторую обработку данных и применяет пользовательский атрибут ячейки сетки на основе результатов. Как только это будет сделано, сетка станет медленным кошмаром для работы.
Есть ли способ убрать этот ужасный удар по производительности и сохранить пользовательские атрибуты ячейки? Я подозреваю, что ответ довольно прост для тех, кто знает внутреннюю работу сетки и ее атрибуты ячейки.
Благодарю.
1 ответ
Установка атрибута ячейки добавит новый GridCellAttr
к списку GridCellAttrProvider
, По мере роста списка поиск определенного атрибута для ячейки (путем итерации по списку и сравнения координат) становится все медленнее и медленнее.
Вы можете попытаться ускорить его, внедрив свой собственный PyGridTableBase.SetAttr
а также GetAttr
(используя dict например):
РЕДАКТИРОВАТЬ: Обновлен код, чтобы позволить перезаписывать атрибуты и эмулировать владение атрибутом реализации по умолчанию
class MyTable(wx.grid.PyGridTableBase):
atts = {}
def Hash(self,row,col):
#FIXME: assumes a constant number of rows and rows > cols
return col + row * self.GetNumberRows()
def SetAttr(self,attr,row,col):
HASH = self.Hash(row, col)
if HASH in self.atts:
# decrement usage count of existing attr
self.atts[HASH].DecRef()
#assign new attribute
self.atts[HASH] = attr
def GetAttr(self,row,col,kind):
HASH = self.Hash(row, col)
if HASH in self.atts:
attr = self.atts[HASH]
attr.IncRef() # increment reference count
return attr
return None
Чтобы разрешить установку целых строк и столбцов, вам также необходимо реализовать:
def SetRowAttr(self,attr,row):
for col in range(self.GetNumberCols()):
attr.IncRef() # increment reference count for SetAttr
self.SetAttr(attr,row,col)
attr.DecRef() # attr passed to SetRowAttr no longer needed
def SetColAttr(self,attr,col):
for row in range(self.GetNumberRows()):
attr.IncRef()
self.SetAttr(attr,row,col)
attr.DecRef()
ПРИМЕЧАНИЕ: при прохождении GridCellAttr
в Set*Attr()
реализация по умолчанию станет владельцем атрибута. Чтобы повторно использовать тот же атрибут (например, хранящийся в переменной класса), вы должны Clone()
увеличить или увеличить счетчик использования (IncRef()
) прежде чем передать его Set*Attr()
метод (клонирование может увеличить потребление памяти).
В приведенном выше примере отсутствует правильное удаление атрибутов: SetAttr()
может проверить None attr и уменьшить счетчик ссылок в указанных координатах, а затем удалить запись из dict. SetCol/RowAttr()
можно оптимизировать, добавив dicts для row и col, аналогично SetAttr()
, GetAttr()
затем может проверить существующую запись в строке и col, и объединить / переопределить атрибут (ы) с атрибутом из ячейки dict (это принцип, используемый реализацией по умолчанию). Для правильной очистки dict(s), позвоните DecRef
на каждой записи до .clear()
,
В качестве альтернативы, вы можете получить из wx.grid.GridCellAttrProvider
и прикрепить его с PyGridTableBase.SetAttrProvider()
, Однако это предотвратит прямой доступ к столу.