Добавление тысяч элементов в виджет таблицы без замораживания окна

#python #pyqt #pyside #qthread #qtablewidget

Вопрос:

У меня есть виджет таблицы, в котором я добавляю тысячи строк. Проблема в том, что каждый раз, когда я добавляю строку, она обновляет окно, в результате чего для завершения всего процесса требуется около 30 секунд, и все это время окно полностью не реагирует. Одним из небольших решений, которое я нашел, было скрыть таблицу, добавить все строки, а затем отобразить таблицу, что значительно сокращает время, в течение которого окно не отвечает, но мне интересно, есть ли способ добавить строки в таблицу, не замораживая окно вообще и не видя, как строки добавляются по отдельности. Я просмотрел другие ответы, в которых используется QThread, но они не сработали для меня, потому что в этих решениях основной поток по-прежнему добавляет строки(что занимает больше всего времени) в таблицу, в результате чего главное окно по-прежнему не отвечает

Пример кода:

 import sys
from time import time
from PySide6.QtWidgets import QTableWidget, QPushButton, QHeaderView, QApplication, QMainWindow

class window(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setFixedSize(1600, 900)

        self.table = QTableWidget(self)
        self.table.setFixedSize(1600, 900)
        self.table.setColumnCount(5)
        self.table.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
        self.table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
        self.table.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch)
        self.table.horizontalHeader().setSectionResizeMode(3, QHeaderView.Stretch)
        self.table.horizontalHeader().setSectionResizeMode(4, QHeaderView.Stretch)

        self.show()

        self.populate_table()

    def populate_table(self):
        start = time()
        # self.table.hide()
        for i in range(2000):
            row = self.table.rowCount()
            self.table.insertRow(row)
            for i_ in range(5):
                item = QPushButton("filler")
                self.table.setCellWidget(row, i_, item)
        print(f"took {time() - start} seconds")
        self.table.show()


if __name__ == '__main__':
    app = QApplication([])
    Gui = window()
    sys.exit(app.exec())
 

Комментарии:

1. Потоковая передача, безусловно, не является решением, поскольку проблема здесь заключается только в управлении пользовательским интерфейсом (что может происходить только в основном потоке). Наиболее важные вопросы: 1. Действительно ли вам нужно устанавливать кнопки в качестве виджетов элементов для каждой строки? Настройка виджетов в представлениях элементов может стать проблемой производительности для очень больших моделей, и вместо этого вы можете предпочесть пользовательский делегат. 2. Известно ли количество строк до начала процедуры? Потому что если это так, то некоторое улучшение может быть достигнуто за счет установки нового числа строк только один раз (перед первым циклом для) вместо добавления одной строки для каждого цикла.

2. Если у вас включена сортировка, это может сделать скорость обновления в больших таблицах очень медленной. Отключение сортировки перед добавлением, а затем ее повторное включение может помочь. Приведенный выше комментарий о том, чтобы не добавлять виджеты, также уместен. Наконец, если производительность действительно важна, рассмотрите возможность использования QTableView с пользовательской моделью вместо QTableWidget. В этом случае вы действительно можете намного больше оптимизировать производительность, и я увидел существенное улучшение при перемещении больших наборов данных в MVC вместо использования виджетов «все в одном».

3. В моем реальном графическом интерфейсе я не использую кнопки, но вместо этого у меня есть множество виджетов для каждой строки. Я просто подумал, что для примера было бы проще, если бы я просто сделал это с помощью кнопок. Не могли бы вы, пожалуйста, объяснить, что вы подразумеваете под пользовательской моделью? Количество строк известно и раньше, поэтому я попробую это сделать, когда у меня будет возможность.

4. Я определенно рассмотрю возможность использования QTableView, когда у меня будет время, но это совершенно ново для меня. Я не думаю, что отключение сортировки сильно изменит время, но я попробую это сделать. Не могли бы вы объяснить, что такое MVC?