|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
#1
|
||||
|
||||
Ошибка при частой Repaint
Есть главная форма, на ней ListBox в котором вручную (onDrawItem) отрисовываются итемы, используя какую-то информацию для заполнения.
Есть функция, назовём её RefreshInform, которая собирает эту информацию, и в конце запускает ListBox.repaint, чтобы onDrawItem нарисовал итемы. При запуске главной формы, через отдельный юнит, запускается бесконечный поток, суть которого - через каждые 100 мс запускать Synchronize(MainForm.RefreshInform). И вот тут меня ждала проблема. Через 5-10 минут работы, всё зависает и падает, а отладчик пишет "out of system resources" несколько раз, а затем "Stack overflow" и стек забит WM_PAINT. Ну логично - забило, только вот почему? Сделал у функции RefreshInform некий глобальный флаг, который в начале устанавливается в False, а по окончанию в True, и, соответсвенно, в потоке перед вызовом RefreshInform стоит проверка этого флага. - Всё-равно падает. Начал читать гугл, нашёл некую информацию, что repaint - виртуальный метод или что-то типа этого, мол используйте refresh он сделан для совместимости. Ок, сделал, запускаю - не помогло, такая же проблема. Читаю дальше, нахожу, что repaint и refresh делают принудительную перерисовку, а чтобы перерисовка была в порядке очереди, - используйте Invalidate, ок делаем так. Теперь проблема уменьшилась до одного сообщения "out of system resources", но так же всё зависает сначала, потом ошибка и всё падает. Знаю что проблема именно в потоке из-за запуска функции RefreshInform в которой запускается выполнение перерисовки, - получается эдакая постоянная перерисовка. А если поставить условие, что например если в listbox изменился count, тогда запускать RefreshInform - все работает стабильно. Нужна помощь. Суть всей этой балды, что бы в ListBox всегда была актуальная информация из-за постоянного обновления в потоке. Использовать банальное ListBox.String[i]:='Бла-бла-бла' - не получится, т.к. ListBox у меня является не более чем "контейнер" для строк, а содержимое строк рисуется из массива, поэтому реальные строки ListBox остаются пустыми, не содержат текста. Програмистами не рождаются, ими становятся! Последний раз редактировалось SCrat.ORS, 11.06.2015 в 18:41. |
#2
|
||||
|
||||
Зачем поток? Почему не обычный таймер?
— Как тебя понимать? — Понимать меня не обязательно. Обязательно меня любить и кормить вовремя. На Delphi, увы, больше не программирую. Рекомендуемая литература по программированию |
#3
|
||||
|
||||
Ну там такой фокус, что если количество итемов увеличелось, то выводится сообщение. Всё это нужно чтобы управление главной формой не останавливалось при показе сообщения. Да и таймер как-то слишком скучно, да и лишняя приблуда на форме.
__________________________________________ А вообще, ты прав. Суть ошибки заключается в том, что как-бы оно не было, поток кидает сообщение на перерисовку, а потом уже главная форма смотрит флаги и запускает перерисовку, но очередь сообщений из-за потока продолжает увеличиваться... Поэтому ставь флаги или не ставь, - сообщение от потока в очередь один хрен уходит, и по этому стек заполняется хочешь ты того или нет. И что бы вся эта шляпа заработала, единственный выход - это ставить на главную форму таймер, и посылать сообщения через него, причем в начале процедуры таймера - его выключать, после выполнения - включать, А поскольку сообщения кидает таймер - он зависит от главной формы, и в нём уже те самые флаги можно смотреть сразу, выставлять условие - посылать сообщение на перерисовку или нет... И всё стало работать. Програмистами не рождаются, ими становятся! Последний раз редактировалось SCrat.ORS, 11.06.2015 в 21:57. |
#4
|
|||
|
|||
Посмотри, можно ли переписать так, что бы обновление вызывалось только тогда, когда добавляется новый итем. Кстати, если форма с ListBox нормальная (т.е. созданная в нормальном потоке со ссылкой на Application), то при добавлении итема он сам перерисуется. Только делать это надо правильно. Добавлять итем надо из главного потока (VCL), вызывая соотв. код из вторичных потоков через Synchronize. Если у тебя несколько потоков добавляют итимы, то этот код надо вызывать в критической секции.
|
#5
|
||||
|
||||
С добавлением проблем как-раз нету, дело в том, что содержимое итема может меняться "из вне". Поэтому и стоит постоянная перерисовка.
Програмистами не рождаются, ими становятся! |
#6
|
||||
|
||||
не нужно постоянно перерисовывать
Пишу программы за еду. __________________ |
#7
|
|||
|
|||
Цитата:
Ну, значит, перерисовывать только в случае изменения. Более того, еще в отрисовщике проверять - видим ли итем, который надо перерисовать. |