Russian Qt Forum
Ноябрь 25, 2024, 12:34 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: QTableWidget (->setItem()) работает очень медленно  (Прочитано 16981 раз)
PinkPanther
Самовар
**
Offline Offline

Сообщений: 169



Просмотр профиля
« : Май 08, 2013, 07:16 »

Здравствуйте.
На панели имеется виджет QTableWidget, данные в таблицу вносятся перед обработкой (она довольно простая и занимает мало времени). 5 столбцов, изменяемое количество строк (выставляется в начале цикла наполнения перед setRowCount(). Обычно количество строк не превышает 3000 (как правило их около 500).
При загрузке программы виджет заполняется данными по умолчанию (те самые 3000 строк).
Когда пользователь меняет настройки отображения данных в таблице (крутит переключатели), посылается сигнал перезаполнить таблицу. По идее, это должно происходить достаточно быстро, чтобы пользователь не заметил задержки.
В итоге при первом запуске, со всеми данными, таблица создается и рисуется на экране примерно за 0,4 секунды. Не мгновенно, но терпимо.
Но при любом следующем вызове той же функции - скачать данные из базы, обработать, заполнить табличный виджет - время создания и рисования увеличивается в 50 раз (!). Исходная таблица 5х3000 создается 20 секунд. Из них (как показали замеры скорости) на создание QTableWidgetItem-ов и их наполнение данными уходит ~0,3 секунды, данные из базы приходят за 0,002 секунды, а сам блок из setItem-ов забирает все остальное время. Естественно, при такой скорости пользоваться программой невозможно, потому что менять данные в этой таблице приходится часто.
Пробовал ->clear(), ->hide() и ->show(), ->setUpdatesEnabled(true/false) - ничего не помогло. Предварительное удаление того, что было в ячейке (removeCellWidget()) - тоже.
В чем проблема задержки при повторной загрузке данных в таблицу, и как она может быть решена?
« Последнее редактирование: Май 08, 2013, 07:21 от PinkPanther » Записан

Эвтаназия - наше хобби!
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #1 : Май 08, 2013, 07:23 »

Сортировка включена?
Записан

Qt 5.11/4.8.7 (X11/Win)
PinkPanther
Самовар
**
Offline Offline

Сообщений: 169



Просмотр профиля
« Ответ #2 : Май 08, 2013, 07:40 »

Сортировка включена?

В таблице сортировка работает (значит, включена).
Выключил перед созданием и включил после всех манипуляций - результат тот же:
0.4 секунды при запуске программы и 18,5 секунд при повторной загрузке.

Вот тут http://stackoverflow.com/questions/4031168/qtableview-is-extremely-slow-even-for-only-3000-rows у человека были похожие проблемы, но он, кажется, справился (через hide и show). Мне это не помогло. Да, ее не видно во время создания, но создается все равно почти 20 секунд.
Записан

Эвтаназия - наше хобби!
PinkPanther
Самовар
**
Offline Offline

Сообщений: 169



Просмотр профиля
« Ответ #3 : Май 08, 2013, 08:42 »

PS Методом проб и ошибок пришел к выводу, что бешеные задержки вызваны удалением QTableWidgetItem-ов при внесении изменений в таблицу, и, вероятно, при этом вызывается сборщик мусора. Кое-как удалось заставить работать код быстро (создал двумерный массив указателей QTableWidgetItem прямо в классе), но сработало только на усечение: элементы, которые были в таблице и остались в новой версии таблицы, не удаляются! А при попытке расширить диапазон значений прога вылетает, так как эти объекты не вошли в новую таблицу и были удалены.

Напрашивается вопрос: можно ли заставить QTableWidget НЕ УДАЛЯТЬ QTableWidgetItem?
Записан

Эвтаназия - наше хобби!
RedDog
Гость
« Ответ #4 : Май 08, 2013, 09:33 »

Напрашивается вопрос: можно ли заставить QTableWidget НЕ УДАЛЯТЬ QTableWidgetItem?
А зачем создавать каждый раз новый итем? Не легче старому присвоить новое значение? QTableWidgetItem::setText(...)
Записан
PinkPanther
Самовар
**
Offline Offline

Сообщений: 169



Просмотр профиля
« Ответ #5 : Май 08, 2013, 11:26 »

Здравая мысль, я так и хотел сделать - создал массив ссылок Item в классе, с запасом, инициализировал их в конструкторе, там же раз и навсегда записал им свойства типа шрифта и расположения, а потом, при необходимости, записывал в них данные и менял rowCount таблицы.
Проблема в том, что если количество строк таблицы уменьшается, а потом опять увеличивается, то айтимы, которые были на этом месте раньше, уничтожаются. Поэтому этот способ работает только тогда, когда мы уменьшаем таблицу. Не менять размер таблицы нельзя: неудобно, к тому же при сортировке вверху будут появляться пустые строки.

Проблема должна быть решена как-то иначе, потому что первая заливка данных в таблицу происходит быстро - и тем же кодом, что и в следующие разы, когда возникают тормоза.
Записан

Эвтаназия - наше хобби!
RedDog
Гость
« Ответ #6 : Май 08, 2013, 11:47 »

А зачем создавать отдельный массив? QTableWidget уже содержит в себе все необходимое.
Ну либо прямая дорога использовать QTableView со своей моделью.
Записан
PinkPanther
Самовар
**
Offline Offline

Сообщений: 169



Просмотр профиля
« Ответ #7 : Май 08, 2013, 12:27 »

А зачем создавать отдельный массив? QTableWidget уже содержит в себе все необходимое.
Ну либо прямая дорога использовать QTableView со своей моделью.


Спасибо за советы. Писать в Item ячейки tableWidget->item(y,x)->setText(...) за пределы старой таблицы у меня не получилось. Программа вылетает. Этих Item после изменения размеров в таблице просто нет, они старательно и неторопливо вымараны из памяти компьютера, в чем и проблема.
В данном случае задача не в том, чтобы отказаться от существующего кода в пользу новой реализации, а в том, чтобы выяснить, почему возникают тормоза. 250 элементов в секунду - очень медленно. Может быть, кто-то знает решение и попозже откликнется. QTableView - тоже вариант, один из, но все-таки хотелось бы сначала разобраться с QTableWidget, лечится он или нет.
Записан

Эвтаназия - наше хобби!
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #8 : Май 08, 2013, 12:44 »

Удаление элементов QStandardItem, QTreeWidgetItem и QTableWidgetItem очень тормознутое.
Особенно при иерархии просто даже неприлично энергоёмкое и соответственно медленное Грустный
Тут как указывалось выше есть 2 варианта:
1. Переиспользовать существующие.
2. Задействовать QTableView со своей моделью.
Первый вариант реализуется довольно просто.
У каждой строки таблицы должен быть свой уникальный id. Перед обновлением таблицы помечаете все строки как удалённые.
Далее при добавлении новых элементов ищите существующие по id и если находите, то сбрасываете "удалённость" и обновляете элементы строки. Новые строки добавляются в конец. Далее удаляете оставщиеся помеченные как удалённые строки.
Записан

Qt 5.11/4.8.7 (X11/Win)
RedDog
Гость
« Ответ #9 : Май 08, 2013, 12:54 »

Вот только не понятно, зачем удалять каждый раз все и заново создавать?
Удалил строку и хрен с ней - забыли про нее. По оставшимся пробежались циклом и установили нужный текст на давно уже созданные.
Записан
PinkPanther
Самовар
**
Offline Offline

Сообщений: 169



Просмотр профиля
« Ответ #10 : Май 08, 2013, 13:25 »

Вот только не понятно, зачем удалять каждый раз все и заново создавать?
Удалил строку и хрен с ней - забыли про нее. По оставшимся пробежались циклом и установили нужный текст на давно уже созданные.

Пример работы с QTableWidget есть в мануале. Их пример - "динамически создать Item - установить значения - запустить setItem" очень прост, и, если использовать его, при запуске программы выполняется за 0.15 секунды (таблица 1390 строк, 5 столбцов). При следующих запусках того же метода тот же объем данных записывается в ту же таблицу за 6,5 секунды. Я очень надеюсь. что на форуме есть человек, который знает решение этой проблемы, увидит эту ветку, и расскажет, что нужно сделать, чтобы при любом запуске метода таблица наполнялась за 0.15 секунды, а не за 6.5.  Улыбающийся
Записан

Эвтаназия - наше хобби!
RedDog
Гость
« Ответ #11 : Май 08, 2013, 13:29 »

[quote author=PinkPanther link=topic=24735.msg175955#msg175955 date=1Я очень надеюсь. что на форуме есть человек, который знает решение этой проблемы, увидит эту ветку, и расскажет, что нужно сделать, чтобы при любом запуске метода таблица наполнялась за 0.15 секунды, а не за 6.5.  Улыбающийся
[/quote]Уже ж раз 5 сказали, почему так происходит (удаление старых - долгий процесс).
Что надо делать тоже не раз сказали...
Записан
PinkPanther
Самовар
**
Offline Offline

Сообщений: 169



Просмотр профиля
« Ответ #12 : Май 08, 2013, 14:04 »

Уже ж раз 5 сказали, почему так происходит (удаление старых - долгий процесс).
Что надо делать тоже не раз сказали...

Если не знаете ответа на поставленный мною вопрос, пожалуйста, покиньте эту ветку.
Записан

Эвтаназия - наше хобби!
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #13 : Май 08, 2013, 14:09 »

Если не знаете ответа на поставленный мною вопрос, пожалуйста, покиньте эту ветку.
Как-то грубо... Причём RedDog абсолютно прав.
Я уверен, что никто тебе здесь не поможет, ибо проблема в Qt.
Тем более, что QTableWidget изначально рассчитан на работу с небольшим объёмом данных.

Кстати, попробуй перед clear() выключить обработку сигналов самого виджета и его модели:
Код
C++ (Qt)
tw->model()->blockSignals( true );
tw->blockSignals( true );
tw->clear();
tw->blockSignals( false );
tw->model()->blockSignals( false );
 
« Последнее редактирование: Май 08, 2013, 14:29 от GreatSnake » Записан

Qt 5.11/4.8.7 (X11/Win)
Bepec
Гость
« Ответ #14 : Май 08, 2013, 14:28 »

1) отключить напрочь обновление.
2) отключить сортировку.
3) провести операции по изменению-вставке.
4) включить отключенное в первых двух пунктах.
5) посмотреть на результат.
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.336 секунд. Запросов: 23.