PDA

View Full Version : QGraphicsView, QGraphicsScene and QGraphicsItem Problem :(



nudels
25th October 2011, 13:01
Hello Guys :)

Im very new in Qt and have a little Problem, maybe its not a Qt Problem or a thinking error.

Okay lets start ;)
I want to build a GUI that have a modular window architecture. I thought i create a QMainWindow and set a QGraphicsView as the centralWidget.
Now i create a MainScene and set it up to the View and in this Scene i have some buttons (QObejct and QGraphicsItem inherited).
When i click e.g. "ServiceButton" then i emit a Signal from the button to the scene and from the scene to the View.
Now i want to set a new Scene to the View, but first delete the old scene.

At this point my program crashes :/

i hope somebody understands me ;)

But my Problem is, that i don't know if this idear 100% would be work.

Here is my Hole Code:

Main.cpp:


#include <QtGui/QApplication>
#include "mainview.h"

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

QMainWindow* wMain = new QMainWindow();
MainView* mainView = new MainView();
wMain->setWindowFlags(Qt::FramelessWindowHint);
wMain->setCentralWidget(mainView);
wMain->show();

return a.exec();
}



MainView.cpp + .h:


#ifndef MAINVIEW_H
#define MAINVIEW_H

#include <QGraphicsView>
#include "mainscene.h"
#include "basicscene.h"

class MainView : public QGraphicsView
{
Q_OBJECT
public:

MainView(QWidget* parent = 0);
~MainView();

protected:
void resizeEvent(QResizeEvent *event);

public slots:
void createBasicScene();
void createMainScene();

private:
MainScene* m_mainScene;
BasicScene* m_basicScene;

};

#endif // MAINVIEW_H


#include "mainview.h"
#include <QDebug>
#include <QMouseEvent>
#include <QtOpenGL/QtOpenGL>


MainView::MainView(QWidget* parent) : QGraphicsView(parent)
{

qDebug() << "Start GraphicsView";
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff) ;
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOf f);
setGeometry(QRect(0,0,800,480));

m_mainScene = new MainScene();
m_mainScene->setSceneRect(QRectF(rect()));

setScene(m_mainScene);
setRenderHint(QPainter::Antialiasing);
setViewport(new QGLWidget());

connect(m_mainScene, SIGNAL(setBasicScene()), this, SLOT(createBasicScene()));

}

MainView::~MainView()
{
delete m_mainScene;
delete m_basicScene;
}

void MainView::resizeEvent(QResizeEvent *event)
{
QGraphicsView::resizeEvent(event);
}


void MainView::createBasicScene()
{
if(scene() != NULL)
delete scene();
m_basicScene = new BasicScene();
setScene(m_basicScene);
connect(m_basicScene, SIGNAL(setMainScene()), this, SLOT(createMainScene()));
}

void MainView::createMainScene()
{
if(scene() != NULL)
delete scene();
m_mainScene = new MainScene();
setScene(m_mainScene);
connect(m_mainScene, SIGNAL(setBasicScene()), this, SLOT(createBasicScene()));
}


MainScene.cpp + .h:


#ifndef MAINSCENE_H
#define MAINSCENE_H

#include <QGraphicsScene>
#include <QDebug>
#include "roundrectitem.h"
#include <QGraphicsSceneMouseEvent>

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

protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);


public slots:
void buttonService();

signals:
void setBasicScene();

private:
RoundRectItem* rect;
// RoundRectItem* rect2;
// RoundRectItem* rect3;

};

#endif // MAINSCENE_H

#include "mainscene.h"


MainScene::MainScene(QObject* parent) : QGraphicsScene(parent)
{
setSceneRect(0,0,800,480);
qDebug() << "Start MainScene";
QRectF iconRect(-100, -100, 200, 200);
QColor iconColor(214,240,110,128);
rect = new RoundRectItem(iconRect, iconColor);

rect->setObjectName("button");

addItem(rect);

rect->setPos(100,100);

connect(rect, SIGNAL(clicked()), this, SLOT(buttonService()));
}

MainScene::~MainScene()
{
//removeItem(rect);
clear();
}

void MainScene::mousePressEvent(QGraphicsSceneMouseEven t *event)
{

QGraphicsScene::mousePressEvent(event);
qDebug() << "MainScene: Pressed";
// RoundRectItem* child = qgraphicsitem_cast<RoundRectItem*>( itemAt(event->scenePos()));
// if(!child)
// return;

}


void MainScene::buttonService()
{
emit setBasicScene();
}



RoundRectItem.cpp + .h:


#ifndef ROUNDRECTITEM_H
#define ROUNDRECTITEM_H

#include <QGraphicsObject>
#include <QLinearGradient>
#include <QGraphicsDropShadowEffect>
#include <QPropertyAnimation>
#include <QGraphicsRotation>
#include <QGraphicsItem>
#include <QObject>

class RoundRectItem : public QObject, public QGraphicsItem
{
Q_OBJECT
Q_PROPERTY(bool fill READ fill WRITE setFill)
public:
RoundRectItem(const QRectF bounds, const QColor &color);
~RoundRectItem();
QPixmap pixmap()const;
void setPixmap(const QPixmap &pixmap);

QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);

bool fill()const;
void setFill(bool fill);

QString objectName() const;
void setObjectName(const QString &name);

protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);

signals:
void clicked();



private:
QPixmap pix;
bool fillRect;
QRectF bounds;
QLinearGradient gradient;
QGraphicsDropShadowEffect* shadow;
QString m_objectName;


};

#endif // ROUNDRECTITEM_H

#include "roundrectitem.h"
#include <QtGui>
#include <QDebug>
#include <QPainterPath>

RoundRectItem::RoundRectItem(const QRectF bounds, const QColor &color)
: QObject(0), QGraphicsItem(), fillRect(false), bounds(bounds)
{
gradient.setStart(bounds.topLeft());
gradient.setFinalStop(bounds.bottomRight());
gradient.setColorAt(0, color);
gradient.setColorAt(1, color.dark(200));
setCacheMode(ItemCoordinateCache);

shadow = new QGraphicsDropShadowEffect();
shadow->setBlurRadius(50);
shadow->setColor(QColor(0x40,0x40,0x40,255));
setGraphicsEffect(shadow);

m_objectName = "x";

}

RoundRectItem::~RoundRectItem()
{
delete shadow;
}


QPixmap RoundRectItem::pixmap()const
{
return pix;
}

void RoundRectItem::setPixmap(const QPixmap &pixmap)
{
pix = pixmap;

setFlags(flags() | QGraphicsItem::ItemIsSelectable);
update();
}

void RoundRectItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
painter->setPen(Qt::NoPen);
painter->setBrush(QColor(0,0,0,64));
painter->drawRoundRect(bounds.translated(2,2));
// painter->drawRoundRect(bounds);

if(fillRect)
painter->setBrush(QApplication::palette().brush(QPalette::W indow));
else
painter->setBrush(gradient);
painter->setPen(QPen(Qt::black,1));
painter->drawRoundRect(bounds);

if(!pix.isNull())
{
painter->scale(1.95,1.95);
painter->drawPixmap(-pix.width() /2, -pix.height()/2, pix);
}
else{

QPainterPath* path = new QPainterPath();
QFont serifFont("Times", 20, QFont::Bold);
path->addText(bounds.center().x(),bounds.center().y(), serifFont, m_objectName);
painter->drawPath(*path);
}
}

bool RoundRectItem::fill() const
{
return fillRect;
}


void RoundRectItem::setFill(bool fill)
{
fillRect = fill;
update();
}

QString RoundRectItem::objectName() const
{
return m_objectName;
}

void RoundRectItem::setObjectName(const QString &name)
{
m_objectName = name;
}

QRectF RoundRectItem::boundingRect()const
{
return bounds.adjusted(0,0,2,2);
}

void RoundRectItem::mousePressEvent(QGraphicsSceneMouse Event *event)
{

// QGraphicsItem::mousePressEvent(event);
qDebug() << "RoundRectItem: Pressed";
emit clicked();

}


The BasicScene is just Similar to MainScene.

Or can i made my idear in another way to change the scene's or Views?

Thank for Help :)

Best regards

nudels

dennis81
25th October 2011, 14:17
so vielleicht?



connect(m_mainScene, SIGNAL(setBasicScene()), this, SLOT(createBasicScene()), Qt:QueedConnection);



if(scene() != NULL)
m_basicScene->deleteLater();
m_basicScene = new BasicScene();
setScene(m_basicScene);
connect(m_basicScene, SIGNAL(setMainScene()), this, SLOT(createMainScene()));

nudels
26th October 2011, 10:41
Hey dennis81,

thanks for ur reply :)

now i have solced my problem and get a new one :D
when i click on my scene then i get a debug output: "MainScene: Pressed". thats all right, but when i click now on a roundrectitem in the scene, then i get this output:
"RoundRectItem: Pressed
MainScene: Pressed"

but i dont want that the scene gets an MousePressEvent, because i just want to "press" the RoundRectItem.
How can i made this? do i need an eventFilter in the Scene?

And another question i have:
Is it better, when i make my own SceneItems like RoundRectitem, to inherit from QGraphicsItem or QGraphicsObject?

I ask, because when i inherit from QGraphicsItem and QObject and want to Animate like move in x-direction, then i need to create a new Q_PROPERTY. But when i inherit from QGraphicsObejct, then i have more defined Propertys, which i can animate.

Thanks for helping ;)

with best regards :)

nudels

stampede
26th October 2011, 11:01
How can i made this? do i need an eventFilter in the Scene?
You can call event->accept() in rect item, and test if event->isAccepted() in scene mousePressEvent.
About your second question, I think you answered it yourself - if inheriting from QGraphicsItem requires you to do more work, isn't it better to use QGraphicsObject ?