LINUX.ORG.RU

[Qt] QGraphicsView background

 


0

0

Есть QGraphicsView, требуется чтобы его задний фон не зависел от масштабирования и скроллинга. То есть всегда отображался одинаково. картинка оригинал

для прорисовки фона используется такой код:

void MainView::drawBackground(QPainter *painter, const QRectF &rect)
{
    painter->save();
    QLinearGradient backgroundGradient(rect.left(),rect.top(),rect.left(),rect.bottom());
    backgroundGradient.setColorAt(0, QColor(170, 185, 220));
    backgroundGradient.setColorAt(1, QColor(240, 240, 250));
    painter->setPen(QPen(Qt::NoPen));
    painter->setBrush(QBrush(backgroundGradient));
    painter->drawRect(rect);
    painter->restore();
}

Фон нарисованный таким образом не зависит от масштабирования. увеличенная

Но, из-за переменной rect будет неправильно отображаться при прокрутке. Так как ей передаются значения маленьких прямоугольников на которые сдвигается сцена. после scroll

Что в таких случаях лучше использовать вместо rect? Может быть кто-то уже сталкивался в подобной проблеммой?


painter->setClip( rect );
const QRectF sceneRect = scene()->sceneRect();
...

Далее то же самое, только вместо rect подставить sceneRect.

Dendy ★★★★★
()
Ответ на: комментарий от Dendy

нет, не оно. Вы видимо не совсем поняли условие.

Во-первых, вариант с sceneRect() не подходит, ибо сцены может не быть, а фон рисоваться должен всегда.

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

irq
() автор топика
Ответ на: комментарий от irq

возможно есть какой-то флаг - перерисовывать весь viewport после scroll, вместо его «обновленной части»?

[code]setViewportUpdateMode(QGraphicsView::FullViewportUpdate);[/code] не помогает.

irq
() автор топика
Ответ на: комментарий от irq

РЕШЕНО

решение оказалось простым: Добавить

resetCachedContent();
в
void scrollContentsBy(int dx, int dy);

irq
() автор топика
Ответ на: комментарий от irq

ибо сцены может не быть, а фон рисоваться должен всегда

Хм, тогда тут неувязочка с документацией к методу QGraphicsView::drawBackground():

All painting is done in scene coordinates.

Возможно тогда так:

const QRectF sceneRect = transform().inverted().map( rect );
Dendy ★★★★★
()
Ответ на: комментарий от Dendy

Точнее так:

paintrer->save();
const QRectF boundingRect = transform().inverted().mapRect( rect );
painter->setTransform( QTransform() );
painter->setClip( boundingRect );
const QRectF sceneRect = viewport()->rect();
...
painter->restore();
Dendy ★★★★★
()
Ответ на: комментарий от Dendy

Нет. Вы не правы. Мой код был верным, просто, как оказалось, в конструкторе QGraphicsView указывалось, что задний фон кешируется (а я про это забыл), поэтому надо сбрасывать кэш каждый раз при scroll'инге.

Теперь отностительно sceneRect. В более ранних версия Qt (до какой именно не скажу) был баг: drawBackgound не вызывалось, если scene было NULL. Тролли, признали, что это был баг и исправили его. То есть, если у QGraphicsView сцена не установлена (scene == NULL), то drawBackground вызывается, а вот sceneRect ничего хорошего не вернет.

Относительно документации: все верно. Все внутренности крутятся вокруг локальных координат. Но параметр rect, который передается drawBackground, указывает на прямоугольник, в котором необходимо отрисовать часть фона. А какие он при этом имеет координаты - не наше дело, в контексте данной задачи, разумеется. И разумеется, в качестве этого прямоугольника передается видимая область. В случае включенного кеширования - маленький прямоугольник, где требовалось «дорисовать фон», но именно по причине, что вычислять необходимый «кусок» грдиентной заливки для нас в этом участке было накладно (да и излишне), мы просто перерисовываем фон при необходимости обновления.

irq
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.