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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: Тормоза при отрисовки своего QWidget'a  (Прочитано 5642 раз)
irq
Гость
« : Март 03, 2008, 12:00 »

Пишу программу, работающую с сетью. Было необходимо написать QWidget, который рисует графики скорости входящего и исходящего графика, используя линии разного цвета и обновляется, разумеется ежесекундно. Казалось бы, все хорошо, но есть такое НО: очень сильно тормозит программа (да и процессор грузится сильно) во время отрисовки.
Надеюсь, что кто-нибудь подскажет как можно ускорить (оптимизировать). Есть идея вынести логическую часть в отдельный поток, но я не думаю, что это исправит дело, поскольку логика довольно простая... Ее суть: каждую секнду снимаются показания скорости с сокета и заносятся в QList<int64_t> dlist, uplist; соответственною

Привожу функцию отрисовки:
Код:
void QMyStats::paintEvent(QPaintEvent *)
{
setUpdatesEnabled(false);
paintBorder();
paintScale();
paintGraph();
setUpdatesEnabled(true);
}

void QMyStats::paintBorder()
{
QPainter painter(this);
painter.setWindow(0, 0, 800, 600);
painter.setRenderHint(QPainter::Antialiasing);

painter.save();

QLinearGradient linGrad(20, 50, 180, 250);
linGrad.setColorAt(0, Qt::gray);
linGrad.setColorAt(1, Qt::white);
linGrad.setSpread(QGradient::ReflectSpread);
painter.setBrush(linGrad);
QRectF border(0, 0, 800, 600);
painter.drawRoundRect(border, 5, 5);

QLinearGradient linGrad1(20, 300, 457, 300);
linGrad1.setColorAt(0, QColor(80,80,80));
linGrad1.setColorAt(1, Qt::white);
linGrad1.setSpread(QGradient::PadSpread);
painter.setBrush(linGrad1);

painter.setPen(QPen(col_bg, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));

QRectF border1(20, 20, 760, 560);
painter.drawRect(border1);

painter.setBrush(Qt::black);
QRectF panel(82, 43, 668, 517);
painter.drawRect(panel);
painter.restore();
painter.end();
}


void QMyStats::paintGraph()
{
QPainter painter(this);
painter.setWindow(0, 0, 800, 600);
painter.setRenderHint(QPainter::Antialiasing);
painter.save();
// down traffic
painter.setPen(QPen(col_down, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
for (int i = 0; i < dlist.count()-1; i++ )
{
painter.drawLine(82 + (668*i)/dlist.count(), 551 - 498*dlist.at(i)/speed6 , 82 + (668*(i+1))/dlist.count() , 551 - 498*dlist.at(i+1)/speed6 );
}
painter.restore();
painter.save();
// up traffic
painter.setPen(QPen(col_up, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
for (int i = 0; i < uplist.count()-1; i++ )
{
painter.drawLine(82 + (668*i)/uplist.count(), 551 - 498*uplist.at(i)/speed6 , 82 + (668*(i+1))/uplist.count() , 551 - 498*uplist.at(i+1)/speed6 );
}
painter.restore();
painter.end();
}


void QMyStats::paintScale()
{
QPainter painter(this);
painter.setWindow(0, 0, 800, 600);
painter.setRenderHint(QPainter::Antialiasing);

// draw vertical dot line
painter.save();

painter.setPen(QPen(col_scale, 1, Qt::DotLine, Qt::RoundCap, Qt::RoundJoin));
// Vertical dot-lines gray
for (int i = 1; i <= 22; i++) painter.drawLine(82+i*30, 43, 82+i*30, 560);

// Vertiaval dot-lines white color (main-lines)
painter.setPen(QPen(Qt::white, 1, Qt::DotLine, Qt::RoundCap, Qt::RoundJoin));
for (int i = 0; i <= 4; i++)
{
painter.drawLine(82+(i*75), 43, 82+(i*75), 560);
painter.translate(75,0);
}

painter.restore();
painter.save();

// draw orizzontal dot line
painter.setPen(QPen(col_scale, 1, Qt::DotLine, Qt::RoundCap, Qt::RoundJoin));
for (int i = 0; i <=6 ; i++)
{
painter.drawLine(82, 53+(i*83), 750, 53+(i*83));
}

painter.setPen(QPen(col_axis, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
// draw speed value-consts
painter.drawText(QRectF(50, 542, 20, 20), Qt::AlignRight, "0");
// draw speed value
QRectF a(22, 44, 58, 20);
QRectF b(22, 125, 58, 20);
QRectF c(22, 210, 58, 20);
QRectF d(22, 293, 58, 20);
QRectF e(22, 376, 58, 20);
QRectF f(22, 459, 58, 20);

QFont fnt;
fnt.setPointSize(8);
painter.setFont(fnt);

painter.drawText(a, Qt::AlignRight, QString::fromStdString(Util::formatBytes(speed6)));
painter.drawText(b, Qt::AlignRight, QString::fromStdString(Util::formatBytes(speed5)));
painter.drawText(c, Qt::AlignRight, QString::fromStdString(Util::formatBytes(speed4)));
painter.drawText(d, Qt::AlignRight, QString::fromStdString(Util::formatBytes(speed3)));
painter.drawText(e, Qt::AlignRight, QString::fromStdString(Util::formatBytes(speed2)));
painter.drawText(f, Qt::AlignRight, QString::fromStdString(Util::formatBytes(speed1)));

painter.restore();
painter.end();
}

speed6 - это максимально-достигнутая скорость. Также это максимальная скорость для шкалы speed{1..5} - вычисляются исходя из нее.

Чтобы все не звучало слишком абстрактно прилагаю скриншот...

Буду рад выслушать конструктивные замечания или дельные предложения.

Для большей ясности...
Код:
bool QMyStats::eachSecond()
{
uint32_t tick = GET_TICK();
uint32_t tdiff = tick - lastTick;
if(tdiff == 0)
return true;

int64_t d = Socket::getTotalDown();
int64_t ddiff = d - lastDown;
int64_t u = Socket::getTotalUp();
int64_t udiff = u - lastUp;

// 334 = 668 /2; 2 pixel per 1 line minimum
if ( dlist.count() >= 334) dlist.removeAt(0);
dlist.append(ddiff);

if ( uplist.count() >= 334) uplist.removeAt(0);
uplist.append(udiff);

lastTick = tick;
lastUp = u;
lastDown = d;

if ( (ddiff > speed6) || (udiff > speed6) )
{
setMaxValue( (ddiff > udiff ? ddiff : udiff) );
}

return true;
}

void QMyStats::setMaxValue(int64_t value)
{
speed6 = value;
speed3 = value / 2;
speed1 = speed3 / 3;
speed2 = speed1 + speed1;
speed4 = speed3 + speed1;
speed5 = speed6 - speed1;
update();
}
Записан
Tonal
Гость
« Ответ #1 : Март 03, 2008, 19:33 »

Можа просто Qwt использовать, и не мучиться? :-)

Ну а по смыслу: не надо каждый раз весть график отрисовывать. Или используй scroll, или рисуй в дополнительный буфер.
Записан
Вячеслав
Гость
« Ответ #2 : Март 03, 2008, 21:00 »

Цитировать
for (int i = 0; i < dlist.count()-1; i++ )
   {
      painter.drawLine(82 + (668*i)/dlist.count(), 551 - 498*dlist.at(i)/speed6 , 82 + (668*(i+1))/dlist.count() , 551 - 498*dlist.at(i+1)/speed6 );
   }

А это вообще интересно выглядит ..... в пайнте _каждый_ раз считать координаты Грустный Мя Грустный Дооолго .... Тогда-уж массив структур и считать при добавлении (все кроме деления на speed6)..... И не ленись компилятору чуть помочь он dist.count() каждый раз будет дергать - проще за циклом переменную сунуть(да и в условие цикла тож)

А вообще накойХ контейнер сдался если
Цитировать
if ( dlist.count() >= 334) dlist.removeAt(0);
   dlist.append(ddiff);
проще IMHO простой тупой массив структур и memmove Подмигивающий Или размер планируеться динамический ?

Кстати народ а Tulip'е at и [] одинаковы по реализации ? или как ?
« Последнее редактирование: Март 03, 2008, 22:32 от Вячеслав » Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #3 : Март 03, 2008, 21:56 »

Цитировать
at() can be faster than operator[](), because it never causes a deep copy to occur.

На практике это высказывание подтверждаеться Подмигивающий
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
irq
Гость
« Ответ #4 : Март 04, 2008, 10:01 »

Цитировать
for (int i = 0; i < dlist.count()-1; i++ )
   {
      painter.drawLine(82 + (668*i)/dlist.count(), 551 - 498*dlist.at(i)/speed6 , 82 + (668*(i+1))/dlist.count() , 551 - 498*dlist.at(i+1)/speed6 );
   }

А это вообще интересно выглядит ..... в пайнте _каждый_ раз считать координаты Грустный Мя Грустный Дооолго .... Тогда-уж массив структур и считать при добавлении (все кроме деления на speed6)..... И не ленись компилятору чуть помочь он dist.count() каждый раз будет дергать - проще за циклом переменную сунуть(да и в условие цикла тож)

А вообще накойХ контейнер сдался если
Цитировать
if ( dlist.count() >= 334) dlist.removeAt(0);
   dlist.append(ddiff);
проще IMHO простой тупой массив структур и memmove Подмигивающий Или размер планируеться динамический ?

Кстати народ а Tulip'е at и [] одинаковы по реализации ? или как ?

Да, согласен что вычислять координаты в paint'e - не самый лучый способ, но они изменяются постоянно, если текущее значение скорости превысило максимум (speed6). Наверняка это не самые большие тормоза.
Сейчас копаю в сторону QGraphicsView. Если кто-то с ним работал, буду рад любой помощи, по возможности примерам реализации (qtdemo не в счет).
Записан
Вячеслав
Гость
« Ответ #5 : Март 04, 2008, 12:26 »

Таки возми профайлера и посмотри где тормоза Подмигивающий
А для начала - чуть оптимизируй код - хотя-б count() за цикл выкини .... или рисуй на битмапе,а в пайнт только битмап пихай ....
QGraphicsView - это немнго не из той серии - это IMHO задел для  вещей типа визио \ диа ....
Записан
Tonal
Гость
« Ответ #6 : Март 04, 2008, 13:02 »

Да, и в любом случае, если рисуешь ломаную лучше использовать drawPolyline для всей ломаной, чем отдельные drawLine для сегментов.
В drawPolyline используется некоторое количество оптимизаций - например не прорисовываются дважды концы отрезков.

И всё таки я бы рекомендовал qwt.
Если таки хочется разобраться и всё самому - делай scroll виджету и дорисовывай только то, что изменилось.
Ну и координаты в буфере сдвигай а не рассчитывай всё наново.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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