Могу ли я ускорить оптимизацию использования 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(), Однако это предотвратит прямой доступ к столу.

Другие вопросы по тегам