QT 4.5 - как я могу получить QPainter-устройство в QGraphicsView

Я пытаюсь сделать программу рисования с QT 4.5, поэтому я использую QGraphicsView для холста и QGraphicsScene для хранения нарисованных элементов. По некоторым причинам я просто не мог получить контекст QPainter в своем собственном производном QGraphicsView

class DrawingCanvas : public QGraphicsView
{ 
  DrawingCanvas::DrawingCanvas(QWidget * parent);

 ...
};

DrawingCanvas::DrawingCanvas(QWidget * parent = 0) : QGraphicsView(parent) 
{
  ....
}

void DrawingCanvas::paintEvent(QPaintEvent& paintEventInfo)
{
  // Result in painter not active
  QPainter(this);
  ...
}

Однако, если я изменяю DrawingCanvas, чтобы быть дочерним элементом QWidget, он работает. Видя, что QGraphicsView получен из QAbstractScrollArea, затем QFrame, затем QWidget, я ожидал бы, что код будет работать.

Итак, я думаю, что вопросы:

1) Почему я не могу использовать paintEvent в QGraphicsView для получения активного QPainter? 2) Возможно ли, что я мог бы получить один?

Спасибо заранее!

Ответы

Ответ 1

Если кто-то все еще задается вопросом, возможно ли это как-то, ответ да.

Краткая версия

void DrawingCanvas::paintEvent(QPaintEvent& paintEventInfo)
{
    // Result in painter active
    QPainter(viewport());
    ...
}

Длинная версия

QGraphicsScene не рисует сама по себе, а вместо этого рисует виджет виджета, который вы ему даете, или по умолчанию QWidget.

Покраска на видовом экране вместо этого вы можете достичь наложенной живописи, которая будет выровнена по отношению к виду, а не к сцене. В качестве альтернативы вы можете использовать QGlWidget и его paintOverlayGl().

Также не забудьте установить viewportUpdateMode (QGraphicsView:: FullViewportUpdate), или вы получите рендеринг артефактов. Возможно, более умный способ избежать артефактов, чем обновлять весь просмотр каждый раз, но пока я не столкнусь с проблемами производительности, я оставлю это.

Ответ 2

Правильно, после вытягивания моих волос какое-то время это кажется невозможным, так что вот мое решение. Все, что вы рисуете, должно быть добавлено в QGraphicsScene; поэтому вы получаете от него свою собственную реализацию.

Самый простой способ - определить временный указатель QGraphicsItem для строк, прямоугольников и т.д., которые вы хотите рисовать.

Переопределите событие virtual mousePressed(), mouseMove() и mouseRelease() соответственно. На mousePressed() инициализируйте указатель temp QGraphicsItem и добавьте его в сцену.

Внутри mouseMoved() задайте координаты temp QGraphicsItem соответственно. Для mouseReleased создайте копию временного объекта и добавьте его в сцену и удалите из сцены темный QGraphicsItem (который вы использовали для рисования линий, прямоугольников и т.д.).

Я предполагаю, что мораль этого заключается в том, что в QGraphicsView нет контекста QPainter, и вам лучше игнорировать его paintEvent().

Надеюсь, это поможет кому-то, кто может наткнуться на это.

Ответ 3

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