Быстрое рисование на qDeclarativeItem

Допустим, у нас есть 2 qDeclarativeItem, лежащих друг над другом. Нижний элемент содержит фоновое изображение (большую часть времени остается неизменным). Верхний элемент содержит набор простых элементов (линии, дуги...), которые можно редактировать напрямую с помощью мыши.

Проблема: при рисовании верхнего слоя нижний слой также полностью перерисовывается. Учитывая, что у меня там большое изображение, перекрашивать его очень медленно.

В качестве примера выше сказанного, вот некоторый код.

Q_DECL_EXPORT int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QmlApplicationViewer viewer;
    qmlRegisterType<BottomLayer>("Layer", 1, 0, "BottomLayer");
    qmlRegisterType<UpperLayer>("Layer", 1, 0, "UpperLayer");
    viewer.setMainQmlFile(QLatin1String("qml/main.qml"));

    viewer.setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate);
    viewer.showExpanded();

    return app.exec();
}

Фоновый слой (закрашивание фонового изображения):

BottomLayer::BottomLayer(QDeclarativeItem *parent) : QDeclarativeItem(parent)
{
    setFlag(QGraphicsItem::ItemHasNoContents, false);
    image.load( "../img.png");
}

void BottomLayer::paint(QPainter* painter,const QStyleOptionGraphicsItem* option, QWidget* widget)
{
    painter->drawImage( QRectF(0, 0, 1920, 1080), image );
}

Слой переднего плана (линии рисования):

UpperLayer::UpperLayer(QDeclarativeItem *parent) : QDeclarativeItem(parent)
{
    setFlag(QGraphicsItem::ItemHasNoContents, false);
}

void UpperLayer::mousePosCanvasChanged(QPoint pos)
{
    p2 = pos;
    if(drawing)
      update();
}

void UpperLayer::mouseDownCanvasChanged(QPoint pos)
{
    p1 = pos;
    drawing = true;
}

void UpperLayer::mouseUpCanvasChanged(QPoint pos)
{
    drawing = false;
}

void UpperLayer::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
    QPen pen(Qt::red, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
    painter->setPen(pen);
    painter->drawLine(p1, p2);
}

QML-код

Rectangle {
  width: 1920
  height: 1080
  color: "transparent"

  MouseArea {
      anchors.fill: parent

      onMousePositionChanged: upper_layer.mousePosCanvasChanged(Qt.point(mouseX,mouseY));
      onPressed: upper_layer.mouseDownCanvasChanged(Qt.point(mouseX,mouseY))
      onReleased: upper_layer.mouseUpCanvasChanged(Qt.point(mouseX,mouseY))
  }

  BottomLayer{
      anchors.fill: parent
  }

  UpperLayer {
      id: upper_layer
      anchors.fill: parent
  }
}

Что я пробовал:

Я попытался нарисовать все прямо на экране с помощью viewer.setAttribute(Qt::WA_PaintOnScreen, true), чтобы избежать накладных расходов на буферизацию. Это дает мне желаемую частоту кадров, но все становится мерцающим.

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

Я попытался сделать это с помощью Graphics View Framework, поэтому я могу ограничить область перерисовки прямоугольником клипа элемента переднего плана. Однако это не работает так, как хотелось бы. Если напр. У меня есть линия, идущая из верхнего левого угла в нижний правый угол, clipRectangle покрывает все изображение (снова все медленно).

Я попытался вычислить clipRectangle для каждого элемента переднего плана и передать его update(QRect) и update(QRegion). Это дает мне ту же производительность, что и GraphicsViewFramework, но теперь я могу разделить свои элементы на несколько прямоугольников, перерисовать каждый отдельно и получить еще меньшую область перерисовки. Если я пойду дальше с этим подходом, я смогу обновлять каждый элемент попиксельно и вообще избежать перерисовки фона. Однако у меня есть ощущение, что я делаю что-то не так. Если это возможно сделать таким образом, не есть ли в Qt что-то, что может сделать все за меня?

P.S. Если у вас есть другие идеи, которые я могу попробовать, мне интересно их услышать (прочитать).


person Dorin Botan    schedule 11.10.2016    source источник


Ответы (1)


Если изображение находится ниже всех элементов и его не нужно перемещать, вы, вероятно, могли бы нарисовать его в QGraphicsView'::drawBackground()

person Kevin Krammer    schedule 11.10.2016