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) Могу ли я получить один?

Заранее спасибо!


qt4
person Extrakun    schedule 13.07.2009    source источник


Ответы (3)


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

Укороченная версия

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

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

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

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

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

person r_ahlskog    schedule 02.02.2010

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

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

Соответственно переопределите виртуальные события mousePressed(), mouseMove() и mouseRelease(). В mousePressed() инициализируйте временный указатель QGraphicsItem и добавьте его на сцену.

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

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

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

person Extrakun    schedule 13.07.2009
comment
Я только что прошел точно такой же процесс ›.‹ Можно было бы подумать, что они сделают рисование временных предметов намного проще. Хотя есть и другое решение... перекрашивание. Вы можете наложить невидимый виджет и рисовать на нем, если хотите. - person mpen; 31.08.2009

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

person James Turner    schedule 11.10.2011