PDA

View Full Version : paintEvent on QGraphicsScene?



sergio87
31st August 2011, 09:53
Hi!

I'm trying to make a program that draws a ellipse over an image when you click. I¡ll explain:

I open an image with QGraphicsScene (subclassed). In the subclass I override the mouseReleaseEvent to collect the mouse clicks. I want to draw an ellipse when click the mouse in these coordinates. The coordinates are from the image and not from the window.

This is the code, based on a example of QT:
SubQGraphicsScene.cpp


SubQGraphicsScene::SubQGraphicsScene(QObject *parent)
: QGraphicsScene(parent)
{
// TODO Auto-generated constructor stub
}

SubQGraphicsScene::~SubQGraphicsScene() {
// TODO Auto-generated destructor stub
}

void SubQGraphicsScene::mouseReleaseEvent(QGraphicsScen eMouseEvent* event)
{
ultimo_x = event->scenePos().x();
ultimo_y = event->scenePos().y();
if (event->button() == Qt::LeftButton){
cout << "Right button :" << ultimo_x << ", " << ultimo_y << endl;
}else{
cout << "Left button :" << ultimo_x << ", " << ultimo_y << endl;
}
update();
this->update();
}

void SubQGraphicsScene::paintEvent(QPaintEvent *event){
cout << "PAINTER" << endl;
//QGraphicsScene::paintEvent(event);
//painter.begin(this);
painter.setPen(QColor("#FF0000"));
//painter.setBrush(QColor("#FFAAAA"));
//Draw reference points
painter.drawEllipse(ultimo_x,ultimo_y,20,20);
//Draw points
painter.end(); // close the painter
}

SubQGraphicsScene.h:


#ifndef SUBQGRAPHICSSCENE_H_
#define SUBQGRAPHICSSCENE_H_
#include <QGraphicsScene>
#include <QPainter>
#include <QtGui>

QT_BEGIN_NAMESPACE
class QPaintEvent;
QT_END_NAMESPACE

class SubQGraphicsScene : public QGraphicsScene
{
Q_OBJECT
public:
SubQGraphicsScene(QObject *parent = 0);
virtual ~SubQGraphicsScene();

private:
void mouseReleaseEvent(QGraphicsSceneMouseEvent* event);
QPainter painter;
int ultimo_x;
int ultimo_y;

protected:
void paintEvent(QPaintEvent *event);
};

#endif /* SUBQGRAPHICSSCENE_H_ */

SvgView.cpp:


SvgView::SvgView(QWidget *parent)
: QGraphicsView(parent)
, m_renderer(Native)
, m_svgItem(0)
, m_backgroundItem(0)
, m_outlineItem(0)
{
mScene = new SubQGraphicsScene(this);
setScene(mScene);
setTransformationAnchor(AnchorUnderMouse);
setDragMode(RubberBandDrag);
setViewportUpdateMode(FullViewportUpdate);

// Prepare background check-board pattern
QPixmap tilePixmap(64, 64);
tilePixmap.fill(Qt::white);
QPainter tilePainter(&tilePixmap);
QColor color(220, 220, 220);
tilePainter.fillRect(0, 0, 32, 32, color);
tilePainter.fillRect(32, 32, 32, 32, color);
tilePainter.end();

factor = 1.0;

setBackgroundBrush(tilePixmap);
}

void SvgView::drawBackground(QPainter *p, const QRectF &)
{
p->save();
p->resetTransform();
p->drawTiledPixmap(viewport()->rect(), backgroundBrush().texture());
p->restore();
}

void SvgView::openFile(const QFile &file)
{
if (!file.exists())
return;
//QGraphicsScene *s = scene();

mScene->clear();
resetTransform();

QPixmap pix( "C:\\i3s\\FotosINPUT\\prueba.JPG" );
mScene->addPixmap(pix);
mScene->update();
}

void SvgView::setRenderer(RendererType type)
{
m_renderer = type;

if (m_renderer == OpenGL) {
#ifndef QT_NO_OPENGL
setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
#endif
} else {
setViewport(new QWidget);
}
}

void SvgView::setHighQualityAntialiasing(bool highQualityAntialiasing)
{
#ifndef QT_NO_OPENGL
setRenderHint(QPainter::HighQualityAntialiasing, highQualityAntialiasing);
#else
Q_UNUSED(highQualityAntialiasing);
#endif
}

void SvgView::setViewBackground(bool enable)
{
if (!m_backgroundItem)
return;

m_backgroundItem->setVisible(enable);
}

void SvgView::setViewOutline(bool enable)
{
if (!m_outlineItem)
return;

m_outlineItem->setVisible(enable);
}

void SvgView::paintEvent(QPaintEvent *event)
{
if (m_renderer == Image) {
if (m_image.size() != viewport()->size()) {
m_image = QImage(viewport()->size(), QImage::Format_ARGB32_Premultiplied);
}

QPainter imagePainter(&m_image);
QGraphicsView::render(&imagePainter);
imagePainter.end();

QPainter p(viewport());
p.drawImage(0, 0, m_image);

} else {
QGraphicsView::paintEvent(event);
painter.begin(this);
painter.setPen(QColor("#FF0000"));
painter.drawEllipse(100,100,20,20);
painter.end(); // close the painter
}
}

void SvgView::wheelEvent(QWheelEvent *event)
{
if(event->delta()>0){
scale(1.25, 1.25);
factor += 0.25; //Save the scale
}else{
scale(0.75, 0.75);
factor -= 0.25; //Save the scale
}
event->accept();
}

SvgView.h:


class SvgView : public QGraphicsView
{
Q_OBJECT

public:
enum RendererType { Native, OpenGL, Image };

SvgView(QWidget *parent = 0);

void openFile(const QFile &file);
void setRenderer(RendererType type = Native);
void drawBackground(QPainter *p, const QRectF &rect);
void mousePressEvent(QMouseEvent *event);

public slots:
void setHighQualityAntialiasing(bool highQualityAntialiasing);
void setViewBackground(bool enable);
void setViewOutline(bool enable);

protected:
void wheelEvent(QWheelEvent *event);
void paintEvent(QPaintEvent *event);

private:
RendererType m_renderer;

QGraphicsItem *m_svgItem;
QGraphicsRectItem *m_backgroundItem;
QGraphicsRectItem *m_outlineItem;

qreal factor;
SubQGraphicsScene *mScene;
QPainter painter;
QImage m_image;
};


It never draws an ellipse. SubQGraphicsScene::paintEvent never is called. SvgView::paintEvent is called, but not draw...

Can anyone help me, please!

Thanks in advance

wysota
31st August 2011, 09:55
QGraphicsScene doesn't have a paintEvent so it's not suprising your implementation of this method is not called.

sergio87
31st August 2011, 11:04
Thanks!!

So, how can I paint over the image?

Another question, why QGraphicsView doesn't paint?

Thanks a lot!

wysota
31st August 2011, 11:12
So, how can I paint over the image?
You can paint on the viewport of the view, you can paint on the item or you can add an item to the scene. All depends on the effect you want to achieve.


Another question, why QGraphicsView doesn't paint?
You are probably opening the painter on the view and not its viewport.

sergio87
31st August 2011, 11:30
Lots of thanks!


You can paint on the viewport of the view, you can paint on the item or you can add an item to the scene. All depends on the effect you want to achieve.

I'll try to add an item to the scene. Because in the future I would like to paint a lot of points (and that points will be in a file). I'll post the results! :)

Thanks a lot!! :D

sergio87
2nd September 2011, 07:48
I solved it: :p

- FIRST solution:

void SubQGraphicsScene::mouseReleaseEvent(QGraphicsScen eMouseEvent* event)
{
ultimo_x = event->scenePos().x();
ultimo_y = event->scenePos().y();
if (event->button() == Qt::LeftButton){
cout << "Right button :" << ultimo_x << ", " << ultimo_y << endl;
}else{
cout << "Left button :" << ultimo_x << ", " << ultimo_y << endl;
}
addEllipse(ultimo_x-10,ultimo_y-10,20,20);
}

This code draw a ellipse when you click the mouse. This solution is very basic, but it works fine!

- SECOND solution:
For my interest, I subclassed QGraphicsItem and I paint in this class. Then I added it to the scene. It works perfect because I can draw a lot of things (ellipse, lines, etc). And is automatically scaled!

If some has the same problem as me, there is the full code:
svgView.cpp:

#include "svgview.h"
#include <QFile>
#include <QWheelEvent>
#include <QMouseEvent>
#include <QGraphicsRectItem>
#include <QGraphicsSvgItem>
#include <QPaintEvent>
#include <qmath.h>
#include <iostream>
using namespace std;

#ifndef QT_NO_OPENGL
#include <QGLWidget>
#endif

SvgView::SvgView(QWidget *parent)
: QGraphicsView(parent)
, m_renderer(Native)
, m_svgItem(0)
, m_backgroundItem(0)
, m_outlineItem(0)
{
mScene = new SubQGraphicsScene(this);
setScene(mScene);
setTransformationAnchor(AnchorUnderMouse);
setDragMode(RubberBandDrag);
setViewportUpdateMode(FullViewportUpdate);

// Prepare background check-board pattern
QPixmap tilePixmap(64, 64);
tilePixmap.fill(Qt::white);
QPainter tilePainter(&tilePixmap);
QColor color(220, 220, 220);
tilePainter.fillRect(0, 0, 32, 32, color);
tilePainter.fillRect(32, 32, 32, 32, color);
tilePainter.end();

factor = 1.0;
setBackgroundBrush(tilePixmap);
}

void SvgView::drawBackground(QPainter *p, const QRectF &)
{
p->save();
p->resetTransform();
p->drawTiledPixmap(viewport()->rect(), backgroundBrush().texture());
p->restore();
}

void SvgView::openFile(const QFile &file)
{
if (!file.exists())
return;
//QGraphicsScene *s = scene();

mScene->clear();
resetTransform();

QPixmap pix( "C:\\i3s\\FotosINPUT\\prueba.JPG" );
mScene->addPixmap(pix);
mScene->update();
fpPaint = new FingerPrintPainter(mScene->sceneRect());
mScene->addItem(fpPaint);
}

void SvgView::setRenderer(RendererType type)
{
m_renderer = type;

if (m_renderer == OpenGL) {
#ifndef QT_NO_OPENGL
setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
#endif
} else {
setViewport(new QWidget);
}
}

void SvgView::setHighQualityAntialiasing(bool highQualityAntialiasing)
{
#ifndef QT_NO_OPENGL
setRenderHint(QPainter::HighQualityAntialiasing, highQualityAntialiasing);
#else
Q_UNUSED(highQualityAntialiasing);
#endif
}

void SvgView::wheelEvent(QWheelEvent *event)
{
if(event->delta()>0){
scale(1.25, 1.25);
factor += 0.25;
}else{
scale(0.75, 0.75);
factor -= 0.25;
}
event->accept();
}
svgView.h:

#ifndef SVGVIEW_H
#define SVGVIEW_H

#include <QGraphicsView>
#include <QPainter>
#include "SubQGraphicsScene.h"
#include "FingerPrintPainter.h"

QT_BEGIN_NAMESPACE
class QWheelEvent;
class QPaintEvent;
class QFile;
QT_END_NAMESPACE

class SvgView : public QGraphicsView
{
Q_OBJECT

public:
enum RendererType { Native, OpenGL, Image };

SvgView(QWidget *parent = 0);

void openFile(const QFile &file);
void setRenderer(RendererType type = Native);
void drawBackground(QPainter *p, const QRectF &rect);

public slots:
void setHighQualityAntialiasing(bool highQualityAntialiasing);

protected:
void wheelEvent(QWheelEvent *event);

private:
RendererType m_renderer;

QGraphicsItem *m_svgItem;
QGraphicsRectItem *m_backgroundItem;
QGraphicsRectItem *m_outlineItem;

qreal factor;
SubQGraphicsScene *mScene;
QPainter painter;
QImage m_image;

FingerPrintPainter *fpPaint;
};
#endif // SVGVIEW_H
subQGraphicsScene.cpp:

#include "SubQGraphicsScene.h"
#include <QWheelEvent>
#include <QMouseEvent>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsScene>
#include <iostream>
using namespace std;
SubQGraphicsScene::SubQGraphicsScene(QObject *parent)
: QGraphicsScene(parent)
{
// TODO Auto-generated constructor stub
}

SubQGraphicsScene::~SubQGraphicsScene() {
// TODO Auto-generated destructor stub
}


void SubQGraphicsScene::mouseReleaseEvent(QGraphicsScen eMouseEvent* event)
{
ultimo_x = event->scenePos().x();
ultimo_y = event->scenePos().y();
if (event->button() == Qt::LeftButton){
cout << "Botón derecho en :" << ultimo_x << ", " << ultimo_y << endl;
}else{
cout << "Botón izquierdo en :" << ultimo_x << ", " << ultimo_y << endl;
}
addEllipse(ultimo_x-10,ultimo_y-10,20,20);
}

SubQGraphicsScene.h:

#ifndef SUBQGRAPHICSSCENE_H_
#define SUBQGRAPHICSSCENE_H_
#include <QGraphicsScene>
#include <QPainter>
#include <QtGui>

QT_BEGIN_NAMESPACE
class QPaintEvent;
QT_END_NAMESPACE

class SubQGraphicsScene : public QGraphicsScene
{
Q_OBJECT

public:
SubQGraphicsScene(QObject *parent = 0);
virtual ~SubQGraphicsScene();

private:
void mouseReleaseEvent(QGraphicsSceneMouseEvent* event);
QPainter painter;
int ultimo_x;
int ultimo_y;

};

#endif /* SUBQGRAPHICSSCENE_H_ */
SubQGraphicsItem.cpp:

#include "SubQGraphicsItem.h"
#include <QPainter>
#include <time.h>
#include <iostream>
using namespace std;
SubQGraphicsItem::SubQGraphicsItem(QRectF r) {
// TODO Auto-generated constructor stub
rect = r;
}

SubQGraphicsItem::~SubQGraphicsItem() {
// TODO Auto-generated destructor stub
}

void SubQGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *)
{
painter->setPen(Qt::NoPen);
painter->setBrush(Qt::darkGray);
srand ( time(NULL) );
int mRandom;
int mRandom2;
for (int i=0; i<100; i++){
mRandom = rand() % 3312 + 1;
mRandom2 = rand() % 4416 + 1;
painter->drawEllipse(mRandom, mRandom2, 20, 20);
}
}

QRectF SubQGraphicsItem::boundingRect() const
{
return rect;
}
SubQGraphicsItem.h:

#ifndef SubQGraphicsItem_H_
#define SubQGraphicsItem_H_
#include <QGraphicsItem>

class SubQGraphicsItem : public QGraphicsItem
{
public:
SubQGraphicsItem(QRectF r);
virtual ~SubQGraphicsItem();
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
private:
QRectF rect;
};

#endif /* SubQGraphicsItem_H_ */


This code draws 30 random ellipses. :p

I hope it helps someone!! :)

Thanks! :D