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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: При выводе текста через QPainter потребляется много ресурсов  (Прочитано 11540 раз)
Командор
Гость
« : Март 07, 2011, 09:24 »

Мне нужно на виджете выводить текст, который регулярно меняется (либо по сигналам, либо по событиям). Текст вывожу следующим образом:
Код
C++ (Qt)
#include <QtGui>
 
class Widget : public QWidget
{
 
public:
   Widget(QWidget* parent = 0) : QWidget(parent)
   {
        k = 0;
   }
   QPainter Painter;
   int k;
 
   void paintEvent(QPaintEvent* event)
   {
       Painter.begin(this);
       for (int i = 0; i < 30; i++)
       {
           k++;
           Painter.drawText(0, i*24, 200, 24, Qt::AlignVCenter, QString::number(k)+"Text Text"+QString::number(k)+ "Text Text Text Text ");
       }
       Painter.end();
   }
 
   void timerEvent(QTimerEvent* event)
   {
       repaint();
   }
 
   void keyPressEvent(QKeyEvent* event)
   {
       repaint();
   }
 
};
 
 
int main(int argc, char *argv[])
{
   QApplication a(argc, argv);
   Widget w;
   w.show();
   //w.startTimer(50);
 
   return a.exec();
}
 

При нажатии на любую клавишу на экране меняется текст. Если удерживать клавишу, то системный монитор показывает загрузку 20-25% (Windows 7, AMD 5000+). Но если раскомментировать таймер, то загрузка 5-7%. И вот не могу понять, почему при событиях от таймера, которых явно больше, чем при удерживании клавиши, загрузка меньше? Т.е. получается, что при событии от клавиатуры возникают дополнительные задержки. Ни у кого нет соображений?

P.S. Если переменную k обнулить, то видно, что количество  событий от таймера и от клавиатуры примерно одинаково (20-25 раз в секунду). Но загрузка процессора все равно в три раза меньше.
« Последнее редактирование: Март 07, 2011, 13:01 от Командор » Записан
dd
Гость
« Ответ #1 : Март 07, 2011, 14:37 »

Можно по нажатию запускать тайемр, а по отпускании (keyReleaseEvent) удалять его. Как вариант.
Записан
Командор
Гость
« Ответ #2 : Март 07, 2011, 15:53 »

Можно по нажатию запускать тайемр, а по отпускании (keyReleaseEvent) удалять его. Как вариант.

Можно, но у каждого пользователя свои установки клавиатуры (задержка при повторении, число повторений в сек).

Впрочем, увеличил количество элементов в два раза, нагрузка что при таймере, что при клавиатуре почти одинаковая - 30%. Что-то не то. Вот только что наткнулся на этом сайте на PatherCommander, запустил, открыл большую папку, жму вниз - файлы бегут вверх - загрузка 10-12%. Открыл исходники QTreeView и QAbstractItemView - так и не смог найти, каким образом там выводится текст элементов. Насколько я понял drawtext - это самый быстрый способ вывод текста. Но получается, что навороченный QTreeView выводит быстрее моей простейшей реализации.
Записан
dd
Гость
« Ответ #3 : Март 07, 2011, 17:17 »

В том и дело, что интервал разный.
А с моим вариантом будет одинаковый и настраиваемый. Более правильно.
Жрет проц - очень похоже на рекурсию.
Обычно бывает, когда бесконечно перерисовывается окно по какой-нибудь причине.

Надо сделать примерно так:

void keyPressEvent(QKeyEvent* event)
{
    if(!flag)
    {
        flag = true;
        // start timer here
    }
}

void keyReleaseEvent (QKeyEvent*)
{
    if(flag)
    {
        flag = false;
        // stop timer here
    }
}


И еще. Чтоюы рисовало быстрее, откшлючи антиалиасинг текста.
сли он все- таки нужен, несложно сделать, чтобы он отключался на время циклической перерисовки, а потом включался.
Записан
ufna
Гость
« Ответ #4 : Март 07, 2011, 23:31 »

делай update() вместо repaint() - зачем насиловать программу?
Записан
Командор
Гость
« Ответ #5 : Март 07, 2011, 23:49 »

делай update() вместо repaint() - зачем насиловать программу?

Под виндой разницы нет, в линухе небольшая разница есть. update(), как я понял, дает эффект, если есть несколько виджетов, лежащих друг над другом или перескающиеся, тогда регион перерисовки будет объединен и сообщение будет более адекватным, но тут такого нет.

Вообще, я делаю легкий виртуальный listbox. В Qt это велосипед, я понимаю, но легкий (школьник вместо урала). Однако легкости не видно. Понятно, что нужно копать в сторону Qtreeview и создать нужную модель. Но все же интересно, почему элементарный вывод через drawtext так грузит систему. Анти-аллиасинг, бэкграундфил, вывод через простейший drawtext без наворотов типа переноса строк ничего не дали.
Записан
dd
Гость
« Ответ #6 : Март 08, 2011, 00:09 »

Текст рисуется тяжело, это факт.
Прочувствовал это на моб устройствах.
В 4.7 появился класс для быстрой отрисовки редкоизменяемого текста.
Могу ошибиться, вроде QStaticText. В описани изменений к этой версии он указан, на сайте глануть можно.

---------- Добавлено -----------
http://www.kubuntu.ru/node/6945 - тут написано про это

А вообще раз 50 миллисекунд рисовать 30 строк - это похоже на алгоритмическую ошибку.
Если в реальности такая нагрузка имеет место быть (например при прогрутке), проще делать рендеринг в пиксмап и его крутить.
Или юзать механизм скроллинга, или другие способы оптимизации.
« Последнее редактирование: Март 08, 2011, 00:16 от dd » Записан
Командор
Гость
« Ответ #7 : Март 08, 2011, 00:29 »

Если в реальности такая нагрузка имеет место быть (например при прогрутке), проще делать рендеринг в пиксмап и его крутить.
Или юзать механизм скроллинга, или другие способы оптимизации.

А можно классы-функции? А именно - рендеринг в пиксмап, скроллинг? Скроллинг  смотрел, там вроде обычный move() вьюпорта, который в конце концов вызывает repaint/update с регионом. Мне нужна прокрутка, но построчная, думал ее сделать виртуальной, т.е. просто отрисовывать в определенных местах текст. Одно успокаивает - что в эксплоэре загрузка 20-30% при прокрутке списка. Но не успокаивает, что в PatherCommander при "тупом" наследовании рисование быстрее, 10% загрузки процессора. Тотал и фригейт столько занимают, а по крайней мере тотал нынешиний все еще пишется на Делфи 2. Т.е. чисто технически, в этом плане новейший Qt не уступает Делфи 2. Но вот мне это недоступно, нахожусь на уровне эксплоера.
« Последнее редактирование: Март 08, 2011, 00:34 от Командор » Записан
dd
Гость
« Ответ #8 : Март 08, 2011, 00:40 »

Скроллинг виджета реализован побитовым копированием. То есть максимально быстро.
Однако оно должно быть отрисовано уже, то есть не прокатит с вариантом "виртуального" списка (из термина MS).
На самом деле не вижу проблемы. Тормозит при прокрутке? Оптимизируй, чтобы строки не рисовалисть текстом.
Записан
ufna
Гость
« Ответ #9 : Март 08, 2011, 01:05 »

Под виндой разницы нет, в линухе небольшая разница есть.

Разве? update() кидает сие событие в очередь, reapint() жестко перерисовывает при вызове. Или я не прав?
Записан
Командор
Гость
« Ответ #10 : Март 08, 2011, 01:28 »

Под виндой разницы нет, в линухе небольшая разница есть.

Разве? update() кидает сие событие в очередь, reapint() жестко перерисовывает при вызове. Или я не прав?

В данном случае лучше repaint(). Потому как если еще добавить селект и "логические" виджеты (т.е. когда вместо цикла drawtext на несколько строк есть несколько дочерних виджетов на несколько строк с одним drawtext и вызывается repaint родителя), то будут тормоза, но только в линухе, винде как я понял в среднем, похрен на update(). Т.е. upadte() лучше понимает линух. Я хочу уточнить. Лет 10 назад я написал свой листбокс на турбопаксаль. Реализованы все основные функции - перемещение вверх-вниз, Pg-Up-down, Home-End, появление-исчезновение объектов в списке. И решил, что сделаю свой qlistbox, охрененно быстрый. Однако "тупо" рисовать текст получается накладно. Буду смотреть в сторону побитового копирования, а новое буду рисовать заново.
Записан
ufna
Гость
« Ответ #11 : Март 08, 2011, 08:28 »

я не вижу чем тут лучше repaint(). Только что глянул доки и они подтвердили мои догадки. repaint() - немедленно вызывает процесс перерисовки, в то время как update() ставит событие в очередь основного цикла. repaint(), кстати, может легко вызывать рекурсию, апдейт - нет. Потому я очень рекомендую использовать апдейт, если нет четкой нужды (а ее по сабжу не видно) перерисовывать моментально.

и да, тормозит если текст - рисуй НЕ текстом, как уже сказали. Техника черт знает каких времен - шрифт растровый, картинками. Кэшируй в слова, тогда при скролле будет быстро бегать ( + во втором потоке всегда можно подрисовывать "не показанные" несколько айтемов для совсем быстрой прокрутки).

На самом деле это для мобильных устройств. Подобный код на десктопе если вызывает такую нагрузку проца - это странно.
Записан
_govorilka
Гость
« Ответ #12 : Март 08, 2011, 10:02 »

Нагрузку на проц скорее всего создаёт алгоритм разбиения текста на строки с последующим их выравниванием. Для рисования текста попробуйте использовать функцию:
Код:
void QPainter::drawText ( const QPoint & position, const QString & text )


Записан
_govorilka
Гость
« Ответ #13 : Март 08, 2011, 10:06 »

и да, тормозит если текст - рисуй НЕ текстом, как уже сказали. Техника черт знает каких времен - шрифт растровый, картинками. Кэшируй в слова, тогда при скролле будет быстро бегать ( + во втором потоке всегда можно подрисовывать "не показанные" несколько айтемов для совсем быстрой прокрутки).

На самом деле это для мобильных устройств. Подобный код на десктопе если вызывает такую нагрузку проца - это странно.

Qt сама создаёт внеэкранный буфер для каждого виджета, рисование картинок здесь мне кажется не поможет. А вот замена repaint() на update() ...
« Последнее редактирование: Март 08, 2011, 10:15 от _govorilka » Записан
ufna
Гость
« Ответ #14 : Март 08, 2011, 10:58 »

Qt сама создаёт внеэкранный буфер для каждого виджета, рисование картинок здесь мне кажется не поможет. А вот замена repaint() на update() ...

поможет и еще как! Надо же правильно буферизировать и кэшировать
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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