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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: оптимизация paint() QGraphicsItem'а  (Прочитано 9307 раз)
AlexeyChe
Гость
« : Март 18, 2011, 12:12 »

Доброго дня!

Ковыряюсь уже давно, но к сожалению не хватает опыта.
Задача нарисовать систему координат +прочие простые элементы, типа квадратиков кружочков, которых может быть не малое количество.
в основе граф.части лежит класс PolarPlot наследованный от QGraphicsView, в конструкторе которого создаётся scene

Код:
plotScene=new QGraphicsScene(0,0,700,700);
    this->setScene(plotScene);
   
после чего добавляется система координат в виде объекта класса PolarAxis наследованного от QGraphicsItem
Код:
    pa = new PolarAxis(350,350,300,cRotate);
    plotScene->addItem(pa);
   
в PolarAxis перегружен метод paint в котором и происходит всё рисование, не буду вдаваться в подробности рисования, ибо оно проходит нормально, да и ничего сложного там нет.

Всё работает, но очень медленно, дебаггер говорит что тот самый метод paint вызывается огромное количество раз, загружая систему под максимум. Про resizeEvent и написанный там scale, и нечего говорить, работает, но медленно.

Погуглил. Нашел Double Buffering. Я может толком его не понял, но пытаюсь сделать таким образом:
всё рисование идет в Pixmap, созданный здесь(конструктор PolarPlot):
Код:
    pa = new PolarAxis(350,350,300,cRotate);
    pm=new QPixmap(rectScene->height(),rectScene->width());
    pa->setPixmap(pm);  //мой метод в котором адрес Pixmap передается в поле данных QPixmap* в PolarAxis
    plotScene->addItem(pa);
   

рисование осуществил в методе класса PolarAxis  drawToBuff(), в котором создается и закрывается QPainter таким образом
Код:
QPainter *p=new QPainter(pm);  //pm - адрес того самого Pixmap'a
//всяческое рисование
p->end();

в PolarAxis::paint()
Код:
    if(!drawOk) drawToBuff();  //читай: если не нарисовано - рисуй!
    p->drawPixmap(0,0,*pm);

итого, рисуется просто черный квадрат
я наверно не правильно использую Pixmap, и рисование в него.

+многопоточность!
я не понимаю саму структуру как мне создать отдельный поток для рисования, посмотрел забугорные примеры, в основном, рисование идет прямо в классе наследованном от QThread, просто процедурой. Единственный ли это способ? хотелось бы сохранить структуру классов адекватной, чтобы рисование было возложено на объекты класса графических элементов.

буду благодарен за помощь
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #1 : Март 18, 2011, 12:19 »

Цитировать
в PolarAxis перегружен метод paint в котором и происходит всё рисование, не буду вдаваться в подробности рисования, ибо оно проходит нормально, да и ничего сложного там нет.
Получается что сей класс помимо осей отрисовывает "простые элементы, типа квадратиков кружочков, которых может быть не малое количество". ?
Записан

Qt 5.11/4.8.7 (X11/Win)
AlexeyChe
Гость
« Ответ #2 : Март 18, 2011, 13:43 »

Получается что сей класс помимо осей отрисовывает "простые элементы, типа квадратиков кружочков, которых может быть не малое количество". ?
Нет, этот класс рисует только ось
в будущем планируется помимо осей добавлять на сцену самостоятельные объекты классов, наследованных от QGraphicsItem, аналогичных PolarAxis
Мне бы хотя бы оси нормально нарисовать
элементы типа квадратиков кружочков я упомянул здесь только для того чтобы показать как необходима адекватная оптимизация


Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #3 : Март 18, 2011, 13:48 »

Пока не покажешь как отрисовываешь элементы и как масштабируешь сцену никто тебе не поможет.
Но, то что сам пытаешься реализовать double-buffering, не решив проблемы с отрисовкой это не есть хорошо, тем более, что оный встроен в Qt.
Записан

Qt 5.11/4.8.7 (X11/Win)
AlexeyChe
Гость
« Ответ #4 : Март 18, 2011, 14:16 »

Пока не покажешь как отрисовываешь элементы...

окей
Код:
void PolarAxis::paint(QPainter *p, const QStyleOptionGraphicsItem *option,QWidget *widget)
{
    p->setMatrix(scale_matrix);
    p->drawEllipse(x-rad,y-rad,rad*2,rad*2);
    p->drawLine(x,y,x,y-rad);

    QPen *dotPen=new QPen(Qt::DashDotLine);
    dotPen->setWidthF(0.3);
    QVector<qreal> dashes;
    dashes <<10 <<10;
    dotPen->setDashPattern(dashes);
    p->setPen(*dotPen);

    for (int i=rad-15;i>0;i-=15)
         p->drawEllipse(x-i,y-i,i*2,i*2);
         for (int i=0; i>-360; i-=10){
             p->drawLine(x,y,x+rad*cos(i*pi/180),y+rad*sin(i*pi/180));
             double x2=x+(rad+20)*cos(i*pi/180+90*pi/180+rotate*pi/180)-15;
             double y2=y+(rad+20)*sin(i*pi/180+90*pi/180+rotate*pi/180)-7.5;
             p->drawText(x2,y2,30,15,Qt::AlignCenter,QString("%1").arg(abs(i)));
         }
}
ничего интересного, тупое рисование.
масштабирование:
Код:
void PolarPlot::resizeEvent(QResizeEvent *re)
{
        QRect *rct=new QRect(0,0,re->size().height()-25,re->size().width()-25);
        plotScene->setSceneRect(*rct);
        double h1=re->size().height();
        double h2=re->oldSize().height();
        double koef=h1/h2;
        pa->rescale(koef);   //в pa объект класса PolarAxis
       
}
//----------------------

void PolarAxis::rescale(float f)
{
    scale_matrix.scale(f,f);  //scale_matrix типа QMatrix, используется первой строчкой в PolarAxis::paint
}
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #5 : Март 18, 2011, 14:23 »

Где PolarAxis::boundingRect() ?
Зачем аллакируете в куче и забываете
Цитировать
QPen *dotPen=new QPen(Qt::DashDotLine);
QRect *rct=new QRect(0,0,re->size().height()-25,re->size().width()-25);
Непонимающий

Зачем при ресайзе меняете размер сцены и потом применяете матрицу?
Чем QGraphicsView::fitInView() не устроил?

Чем не устроил QString::number() при отрисовке числа?
« Последнее редактирование: Март 18, 2011, 14:30 от GreatSnake » Записан

Qt 5.11/4.8.7 (X11/Win)
AlexeyChe
Гость
« Ответ #6 : Март 18, 2011, 14:56 »

Где PolarAxis::boundingRect() ?
Код:
QRectF PolarAxis::boundingRect() const
{
    return QRectF(0,0,rad*2+80,rad*2+80);
}
проект сырой, но если выкладывать весь код, то займет очень много места
без boundingRect ничего бы и не запустилось, так что я перенес этот пункт в категорию "очевидное"

вообще по сути, если убрать всё масштабирование, припонки с double buffering, и прочую ересь, проект будет и так страшно лагать, рисуя только оси

ЗЫ. про FitInView, просто незнал, спасибо
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #7 : Март 18, 2011, 15:06 »

Дело в том, QGraphicsItem заточен под динамику, а PolarAxis по сути статика.
Поэтому предлагаю перенести отрисовку PolarAxis в свою PolarPlot::drawBackground().
Если оставить PolarAxis элементом, то т.к. он является фоном для других мелких элементов, то он будет всегда перерисовываться при изменении последних. А это явные и большие тормоза.

Уже не раз здесь поднималась такая проблема. Странно, что в Qt книжках про такие ньюансы ни слова.
Может когда-нибудь соберусь написать "tips & tricks" про QGraphicsView.
« Последнее редактирование: Март 18, 2011, 15:11 от GreatSnake » Записан

Qt 5.11/4.8.7 (X11/Win)
AlexeyChe
Гость
« Ответ #8 : Март 18, 2011, 15:16 »

GreatSnake, спасибо большое!
и впрямь странно что в книжках нету
только вот на будущее, у меня ведь элементов будет не меньше чем line'ов и string'овых лейблов на осях, что мне почитать чтобы делать нормальное отображение?
да и Pixmap, как правильно его использовать. я руководствовался в основном этой статьей
http://doc.trolltech.com/qq/qq06-flicker-free.html#paintingbycandlelight

сделал через drawBackgroung, нормально, только вот при изменении размеров, или наезде другого окна, то есть при любом намеке на repaint лагает. а значит фиговый встроенный double buffering или я не умею им пользоваться
« Последнее редактирование: Март 18, 2011, 15:34 от AlexeyChe » Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #9 : Март 18, 2011, 21:45 »

Цитировать
или я не умею им пользоваться
Более чем уверен, что именно так)

Цитировать
при любом намеке на repaint лагает
Как это проявляется? Давай код drawBackground().

Записан

Qt 5.11/4.8.7 (X11/Win)
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #10 : Март 18, 2011, 22:05 »

Хм..
Цитировать
Код
C++ (Qt)
void PolarAxis::paint(QPainter *p, const QStyleOptionGraphicsItem *option,QWidget *widget)
{
   p->setMatrix(scale_matrix);
   p->drawEllipse(x-rad,y-rad,rad*2,rad*2);
   p->drawLine(x,y,x,y-rad);
 
   QPen *dotPen=new QPen(Qt::DashDotLine); // Зачем?
   dotPen->setWidthF(0.3);
   QVector<qreal> dashes;
   dashes <<10 <<10;
   dotPen->setDashPattern(dashes);
   p->setPen(*dotPen);
 
   for (int i=rad-15;i>0;i-=15)
        p->drawEllipse(x-i,y-i,i*2,i*2);
        for (int i=0; i>-360; i-=10){
            p->drawLine(x,y,x+rad*cos(i*pi/180),y+rad*sin(i*pi/180));
            double x2=x+(rad+20)*cos(i*pi/180+90*pi/180+rotate*pi/180)-15;
            double y2=y+(rad+20)*sin(i*pi/180+90*pi/180+rotate*pi/180)-7.5;
            p->drawText(x2,y2,30,15,Qt::AlignCenter,QString("%1").arg(abs(i)));
        }
}
 
Во-первых зачем создавать dotPen в куче?
Во-вторых из-за него у вас утечка, поскольку не видно где он уничтожается
В-третьих
Цитировать
Код
C++ (Qt)
void PolarPlot::resizeEvent(QResizeEvent *re)
{
       QRect *rct=new QRect(0,0,re->size().height()-25,re->size().width()-25); // Те же грабли
       plotScene->setSceneRect(*rct);
       double h1=re->size().height();
       double h2=re->oldSize().height();
       double koef=h1/h2;
       pa->rescale(koef);   //в pa объект класса PolarAxis
 
}
 
всё сказанное выше, но приминительно к rct

А теперь представте, что будет при интенсивном ресайзе и отрисовки..
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
AlexeyChe
Гость
« Ответ #11 : Март 19, 2011, 13:11 »

я разобрался с QPixmap и QImage, и отрисовка теперь происходит только тогда когда нужно
и как следствие отсутствуют тормоза
масштабирование через FitInView, и вообще картина стала гораздо лучше,
сейчас буду засовывать сцену в отдельный поток, и тогда вообще будет счастье

всем спасибо, если ещё есть какие нибудь рекомендации, буду благодарен

Цитировать
Во-вторых из-за него у вас утечка, поскольку не видно где он уничтожается
я честно сказать пока не разобрался в memory management qt, я почитаю насчёт этого момента, спасибо

Записан
psgenn
Гость
« Ответ #12 : Март 27, 2011, 13:58 »

А как собственно засунуть сцену в отдельный поток?
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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