Russian Qt Forum

Qt => 2D и 3D графика => Тема начата: _Vitaliy_ от Март 19, 2012, 21:24



Название: [практически решено] определение видимой части QGraphicsScene в QGraphicsView
Отправлено: _Vitaliy_ от Март 19, 2012, 21:24
Доброго времени суток.
Есть вопрос такого характера.

Есть модуль, в конструкторе которого создаю:  
    
Код:
...
    ui->setupUi(this);
    scene = new QGraphicsScene(this);
    ui->graphicsView->setScene(scene);
    ...
далее по коду устанавливаю размер сцены:  
Код:
scene->setSceneRect(0, 0, Size + 50, razmer_sceni_po_y - 30); 
где Size может принимать довольно большое значение.

рисую график
Код:
QGraphicsItem *item = new Grafik(...);  

Возникают "тормоза" при передвижении графика вверх-вниз (нужно по задаче).
Скорее всего происходит из-за того что сцена может быть в несколько десятков раз больше чем визуальный ui->graphicsView и передвигается весь график (включая части которые не видно).

Вопрос: как определить видимую часть QGraphicsScene в ui->graphicsView?


Название: Re: определение видимой части QGraphicsScene в QGraphicsView
Отправлено: GreatSnake от Март 20, 2012, 10:31
Код
C++ (Qt)
ui->graphicsView->mapToScene( QRect( 0, 0,  ui->graphicsView->viewport()->width(),  ui->graphicsView->viewport()->height() ) )


Название: Re: определение видимой части QGraphicsScene в QGraphicsView
Отправлено: _Vitaliy_ от Март 21, 2012, 18:59
GreatSnake спасибо Вам, практически получилось то, что я хотел.

Остается вопрос такого характера.
Если сцена не помещается во вьювере, то появляется горизонтальный скроллер, например я перемещаю скроллер на некоторую позицию, как узнать в этом случае какой участок сцены видно во вьювере?


Название: Re: [практически решено] определение видимой части QGraphicsScene в QGraphicsView
Отправлено: popper от Март 22, 2012, 23:26
Вопрос: как определить видимую часть QGraphicsScene в ui->graphicsView?

как узнать в этом случае какой участок сцены видно во вьювере?

никак не могу понять разницу между этими двумя вопросами


Название: Re: [практически решено] определение видимой части QGraphicsScene в QGraphicsView
Отправлено: Bepec от Март 23, 2012, 08:01
И не пытайся... Это философия Йоды.
"Это есть дерево. Это дерево есть?"


Название: Re: [практически решено] определение видимой части QGraphicsScene в QGraphicsView
Отправлено: _Vitaliy_ от Март 23, 2012, 08:30
Идея в следующем (рассматривается только по ширине):
Вариант 1. При выводе Сцена вмещается в Виев, тогда ничего пересчитывать не надо, просто отрисовать.

Вариант 2. При выводе Сцена гораздо больше Виев, первоначально нулевые координаты Виев и Сцены совпадают но сцена "простирается" вправо и большая часть ее не видна. Вариант, предложенный GreatSnake работает. Можно просчитать какой участок Сцены видим, отрисовать его, а потом все остальное.

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

Напрашивается работать через Скролл, зная размер Виев, размер Сцены и значение скролла (пока не знаю как) можно высчитать видимый участок Сцены.
Может нужно через слот изменения значения скролла...

П.С. Извиняюсь, если "многа букф" но проблему изложил по моему ясно.
П.П.С. Если кто предложит более рациональный вариант, буду премного благодарен.
  


Название: Re: [практически решено] определение видимой части QGraphicsScene в QGraphicsView
Отправлено: Barmaglodd от Март 23, 2012, 09:48
Отрисовывай только видимую часть атема, и никаких пересчётов не надо.
В QGraphicsItem::paint передаётся прямоугольник, который видим QStyleOptionGraphicsItem::exposedRect.
Но если ты набил сцену миллионом айтемов, то ССЗБ ;)


Название: Re: [практически решено] определение видимой части QGraphicsScene в QGraphicsView
Отправлено: GreatSnake от Март 23, 2012, 10:02
П.П.С. Если кто предложит более рациональный вариант, буду премного благодарен.
Абсолютно не понятно в чём проблема и что нужно на выходе и чем не устраивает стандартное поведение GV ???


Название: Re: [практически решено] определение видимой части QGraphicsScene в QGraphicsView
Отправлено: V1KT0P от Март 23, 2012, 11:58
П.С. Извиняюсь, если "многа букф" но проблему изложил по моему ясно.
П.П.С. Если кто предложит более рациональный вариант, буду премного благодарен.
Да не совсем ясно. Если ты добавляешь итемы на графсцену то графсцена сама смотрит какие итемы видны те и перерисовывает.


Название: Re: [практически решено] определение видимой части QGraphicsScene в QGraphicsView
Отправлено: _Vitaliy_ от Март 23, 2012, 13:14
вечером выложу исходники и добавлю немного картинок, дабы не вводить в заблуждение комьюнити.


Название: Re: [практически решено] определение видимой части QGraphicsScene в QGraphicsView
Отправлено: _Vitaliy_ от Март 23, 2012, 19:33
Вот проект.
Сильно не пинайте, только учусь.

В vizual_grifik происходит вызов рисования
Код:
QGraphicsItem *item = new Grafik(model, Qt::red, 3, min, max);
item->setPos(QPointF(0, 200));
grafik отвечает за рисование, остальное можно опустить.

В папке dannie лежат тестовые файлы. Если открыть big-файл то заметны тормоза, особенно при попытке перемещения графиков по оси Y.

П.С. кстати где-то при построении графиков, течет память...


Название: Re: [практически решено] определение видимой части QGraphicsScene в QGraphicsView
Отправлено: _Vitaliy_ от Март 24, 2012, 09:38
Цитировать
Отрисовывай только видимую часть атема, и никаких пересчётов не надо.
В QGraphicsItem::paint передаётся прямоугольник, который видим QStyleOptionGraphicsItem::exposedRect.

А как его туда передать?
В конструкторе я рисую путь
Код:
Grafik::Grafik(QStandardItemModel *model, const QColor &color, int stolbec, int min, int max)

В моем случае boundingRect ограничивается прямоугольником ограничивающим график
Код:
QRectF Grafik::boundingRect() const
{
    return QRectF(0, 0, size_x + 5, size_y);
}
Далее
Код:
QPainterPath Grafik::shape() const
{
    QPainterPath pathik;
    pathik.addPath(path);
    return pathik;
}
И собственно рисование
Код:
void Grafik::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(widget);

    painter->setPen(QPen(color));
    painter->drawPath(path);
}
Нашел в доках что нужно флаг передать:
Код:
This member is only initialized for items that have the QGraphicsItem::ItemUsesExtendedStyleOption flag set.


Название: Re: [практически решено] определение видимой части QGraphicsScene в QGraphicsView
Отправлено: _Vitaliy_ от Март 25, 2012, 12:16
Правильно ли будет использовать следующий алгоритм:
1. В ГрафикВиеве на событии МаусРелиз (пользователь передвинул скролл на некоторую позицию) определяем видимую часть Сцены используя
Код:
graphicsView->mapToScene( QRect( 0, 0,  ui->graphicsView->viewport()->width(),  ui->graphicsView->viewport()->height() ) )
2. Сначала перерисовываем видимую часть сцены а потом невидимые участки сцены.

Пробовал для тема такие флаги
Код:
item->setCacheMode(QGraphicsItem::ItemCoordinateCache); и item->setCacheMode(QGraphicsItem::DeviceCoordinateCache);

В конструкторе тоже пробовал оптимизацию
Код:
ui->graphicsView->setOptimizationFlags(QGraphicsView::DontSavePainterState);
ui->graphicsView->setViewportUpdateMode(QGraphicsView::SmartViewportUpdate);
ui->graphicsView->setCacheMode(QGraphicsView::CacheBackground);
но что-то не заметно прироста, "большой" график все равно "дергается" если его перемещать вверх-вниз...


Название: Re: [практически решено] определение видимой части QGraphicsScene в QGraphicsView
Отправлено: Bepec от Март 25, 2012, 13:31
Зачем невидимые перерисовывать Оо? Они ж невидимые ёмое.


Название: Re: [практически решено] определение видимой части QGraphicsScene в QGraphicsView
Отправлено: _Vitaliy_ от Март 25, 2012, 18:41
Может я не до конца понимаю концепцию рисования...
В одной из форм (пусть будет vizual_grifik) я вызываю:
Код:
QGraphicsItem *itema = new Grafik(model, Qt::green, 4, min, max);
далее в конструкторе (пусть Grafik) рисую path
в этом же модуле Grafik вызывается отрисовка
Код:
void Grafik::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(widget);

    painter->setPen(QPen(color));
    painter->drawPath(path);
}
Если рисовать в непосредственно в paint, то заметны тормоза.
При этом в самой организации кода мне вроде все понятно.

Теперь рассмотрим вариант:
ГрафикСцен"а не умещается в ГрафикВиев, есть скролл по оси ОХ, пользователь передвигает мышкой скролл не некоторую позицию.
В этом случае происходит перерисовка Grafik::paint(...)?
если да, то может есть смысл организовать перерисовку в конструкторе в цикле с видимыми координатами ГрафикСцен в ГрафикВиев или я заблуждаюсь.
Цитировать
Зачем невидимые перерисовывать Оо? Они ж невидимые ёмое.
А если пользователь после перемещения графика по OY передвинет скролл на некоторую иную позицию по OX, то "перемещенный" график будет ли отображаться корректно, т.е. будут ли "артефакты" на графике после того как пользователь сначала перемещал график вверх-вниз, а потом передвинул скроллом сцену во вьюшке?  
Прошу пояснить.
 


Название: Re: [практически решено] определение видимой части QGraphicsScene в QGraphicsView
Отправлено: GreatSnake от Март 26, 2012, 12:34
В папке dannie лежат тестовые файлы. Если открыть big-файл то заметны тормоза, особенно при попытке перемещения графиков по оси Y.
На моей системе (amd phenom II X4 925, CentOS 5.6) абсолютно ничего не тормозит.

Но в любом случае исполльзовать QPainterPath c 16K элементами для простого графика будет очень накладно.
Если включить сглаживание, то даже на моей системе прокрутка вообще не работает - просто полный тормоз - 100% cpu.
Для таких вещей используют QPolygonF и QPainter::drawPolyline() или готовый QGraphicsPolygonItem.


Название: Re: [практически решено] определение видимой части QGraphicsScene в QGraphicsView
Отправлено: _OLEGator_ от Март 26, 2012, 15:04
Для определения области рисования поидее можно воспользоваться этим:

Код
C++ (Qt)
void QGraphicsItem::paint ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0 ) [pure virtual]
QRectF QStyleOptionGraphicsItem::exposedRect

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


Название: Re: [практически решено] определение видимой части QGraphicsScene в QGraphicsView
Отправлено: _Vitaliy_ от Март 26, 2012, 18:29
Цитировать
...игнорировать близкие точки...
нельзя потому что графиков будет порядка 20.
В более ранней версии (пробе) рисовал
Код:
 for (int i = 0; i <= size_x-1; i++)
    {
        x.append(my_model->item(i, stolbec)->text().toFloat());
        pointsss.append(QPointF(i,x[i]));
    }

    painter->setPen(QPen(color, 2));
    painter->save();
    painter->drawPoints(pointsss.data(), pointsss.size());
    painter->restore();
непосредственно в Пэинт но тормоза были еще больше...
Попробую уйти от Патча, потом отпишусь.

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

П.С. не подскажите где у меня "течет отрисовка" с каждым нажатием на кнопку "открыть график" и закрыть порядка 2Мб утекает...

П.П.С. С Qt начал дружить недавно, поэтому если можно ответ(ы) более развернуто.


Название: Re: [практически решено] определение видимой части QGraphicsScene в QGraphicsView
Отправлено: _OLEGator_ от Март 26, 2012, 21:12
Игнорировать близкие точки одного графика конечно же!

Значение прокрутки:

Код
C++ (Qt)
QScrollBar * QAbstractScrollArea::horizontalScrollBar () const
int QAbstractSlider::value () const


Название: Re: [практически решено] определение видимой части QGraphicsScene в QGraphicsView
Отправлено: _Vitaliy_ от Март 26, 2012, 21:29
Цитировать
Игнорировать близкие точки одного графика конечно же!
Нельзя, т.к. графики между собой имеют некоторую зависимость и нужно смотреть на соответствие точек между графиками. Очень важно чтобы точка одного графика была точно под (над) точкой другого.
Завтра на свежую голову попробую код с предложенным скроллом.
А так, спасибо за соучастие.
П.С. случайно нет вариантов, почему память течет?


Название: Re: [практически решено] определение видимой части QGraphicsScene в QGraphicsView
Отправлено: _OLEGator_ от Март 26, 2012, 22:06
Лично я не вижу, где бы сцену чистил в классе vizual_grifik от уже имеющихся в ней объектов.


Название: Re: [практически решено] определение видимой части QGraphicsScene в QGraphicsView
Отправлено: Barmaglodd от Март 28, 2012, 13:27
Цитировать
Отрисовывай только видимую часть атема, и никаких пересчётов не надо.
В QGraphicsItem::paint передаётся прямоугольник, который видим QStyleOptionGraphicsItem::exposedRect.

А как его туда передать?
В конструкторе я рисую путь

Нашел в доках что нужно флаг передать:
Код:
This member is only initialized for items that have the QGraphicsItem::ItemUsesExtendedStyleOption flag set.

у Grafik в конструкторе делаешь setFlag(ItemUsesExtendedStyleOption)
QPainterPath не создаёшь, просто хранишь массив точек.
в void QGraphicsItem::paint ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0 )
у option получаешь exposedRect, это видимая область в координатах Graphik, выбираешь все точки из массива, которые попадают в exposedRect и рисуешь по ним QPainterPath, всё! Никаких скроллов и прочей байды GraphicsView всё само за тебя сделает.


Название: Re: [практически решено] определение видимой части QGraphicsScene в QGraphicsView
Отправлено: _OLEGator_ от Март 28, 2012, 14:00
to Barmaglodd
каждый раз создавать QPainterPath во время отрисовки - весьма накладно и будет тормозить