Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QT 4.5 - how do I get a QPainter device in a QGraphicsView

Tags:

qt4

I am trying to do a painting program with QT 4.5, so I am using the QGraphicsView for the canvas, and QGraphicsScene to store the items drawn. For some reasons, I just couldn't get a QPainter context in my own derived 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);
  ...
}

However, if I change the DrawingCanvas to be a child of QWidget, it works. Seeing that QGraphicsView is derived from QAbstractScrollArea, then QFrame, then QWidget, I would expecting that the code would work.

So I guess the questions are:

1) Why is that I can't use paintEvent in a QGraphicsView to get a active QPainter? 2) Is there possible I could get one?

Thanks in advance!

like image 335
Extrakun Avatar asked Jul 13 '09 05:07

Extrakun


2 Answers

If anyone still is wondering if this somehow is possible, the answer is yes.

Short version

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

Long version

QGraphicsScene does no painting on itself but instead paints on the viewport widget you give it or by default a QWidget.

By painting on the viewport instead you can achieve overlayed painting that will be aligned to the view and not the scene. Alternatively you could use QGlWidget and its paintOverlayGl().

Also remember to set viewportUpdateMode(QGraphicsView::FullViewportUpdate) or you will get rendering artifacts. There might be a smarter way to avoid artifacts than to update the entire view every time but until I encounter performance problems I will let it rest.

like image 115
r_ahlskog Avatar answered Oct 18 '22 09:10

r_ahlskog


Right, after pulling out my hair for a while, this appears to be impossible, so here's my solution. Everything you draw must be added to the QGraphicsScene; so you derive your own implementation from it.

The simplest way is to define a temporary QGraphicsItem pointer for the lines, rectangles and etc which you want to draw.

Override the virtual mousePressed(), mouseMove() and mouseRelease() event accordingly. On the mousePressed(), initialise the temp QGraphicsItem pointer and add it to the scene.

Inside the mouseMoved(), set the temp QGraphicsItem's coordinates accordingly. For the mouseReleased, create a copy of the temp object and add it to the scene, and remove the temp QGraphicsItem (which you have been using for drawing lines, rectangles etc.) from the scene.

I guess the moral of this is that there is no QPainter context within a QGraphicsView, and you are better off ignoring its paintEvent().

Hope this helps someone who may stumble upon this.

like image 4
Extrakun Avatar answered Oct 18 '22 10:10

Extrakun