PDA

View Full Version : QGraphicsView with QGraphicsPixmapItem that resizes on resize of QGraphicsView



shock
26th November 2011, 18:38
Hey Guys,

I subclassed QGraphicsView and an QGraphicsPixmapItem...
What i want: I want to add a Pixmap to the GraphicsView and resize it (if the pixmap does not have it's desired maximum size) on resizing the GraphicsView..

What i receive: an unhandled exception in QPaintDevice::paintingActive()



inline bool QPaintDevice::paintingActive() const
{ return painters != 0; } // seems i get the exception here





BackgroundItem::BackgroundItem(const QPixmap &pixmap)
: QGraphicsPixmapItem(pixmap)
{
myOriginalPixmap = pixmap;
}

QPixmap BackgroundItem::getOriginalPixmap(){
return myOriginalPixmap;
}




void FloorPlanGraphicsView::init()
{
canvas = new QGraphicsScene(this);
//scene->setSceneRect(0,0,this->geometry().width(),this->geometry().height();
setScene(canvas);
setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
}

void FloorPlanGraphicsView::setFloorPlan(const QPixmap &image){
BackgroundItem *backImg = new BackgroundItem(image);//.scaled(geometry().width(),geometry().height(),Qt: :KeepAspectRatio));
scene()->addItem(backImg);
backImg->setPos(0,0);
backImg->setZValue(0);
backImg->setPixmap(image.scaled(geometry().width(),geometry ().height(),Qt::KeepAspectRatio));
}
void FloorPlanGraphicsView::resizeEvent(QResizeEvent *event){
scene()->setSceneRect(0,0,this->geometry().width(),this->geometry().height());

QList<QGraphicsItem*> graphicItems = scene()->items();
for (int i = 0; i < graphicItems.size(); ++i){

if (graphicItems.at(i)->type() == FloorPlanGraphicsView::BackgroundType){
BackgroundItem *myBackItem = qgraphicsitem_cast<BackgroundItem*>(graphicItems.at(i));

if(this->geometry().width() <= myBackItem->getOriginalPixmap().size().width() && this->geometry().height() <= myBackItem->getOriginalPixmap().size().height())
// i get the error immediately here on resize!
myBackItem->setPixmap(myBackItem->getOriginalPixmap().scaled(this->geometry().width(),this->geometry().height(),Qt::KeepAspectRatio));
else
myBackItem->setPixmap(myBackItem->getOriginalPixmap());
}
}
}


The invocation to setFloorPlan() looks like the following:


ui.floorPlan->setFloorPlan(QPixmap::fromImage(QImage::fromData(q uery.value(0).toByteArray())));


Do i have to reimplement a paint() function or something similar here?
Anbody any idea for me?

shock
28th November 2011, 07:13
Has really nobody an idea for me? =/

norobro
29th November 2011, 02:07
Maybe the following is your problem.

From the docs (link (http://doc.qt.nokia.com/latest/qgraphicsitem.html#qgraphicsitem_cast)):
T qgraphicsitem_cast ( QGraphicsItem * item )

Returns the given item cast to type T if item is of type T; otherwise, 0 is returned.
Note: To make this function work correctly with custom items, reimplement the type() function for each custom QGraphicsItem subclass.Check out the diagramscene and elasticnodes examples.

In backgrounditem.h add:
enum { Type = UserType +1 };
int type() const { return Type; }
And in FloorPlanGraphicsView::resizeEvent() change:
//if (graphicItems.at(i)->type() == FloorPlanGraphicsView::BackgroundType){
if (graphicItems.at(i)->type() == BackgroundItem::Type{

shock
30th November 2011, 17:10
Ney norobro!

Thanks for your reply, i have not posted that part of code cauze i thought it might not be useful for a reader - but i am aware of that ..
Here is the code from the header:



class FloorPlanGraphicsView : public QGraphicsView
{
Q_OBJECT

public:
FloorPlanGraphicsView(QWidget * parent = 0);
FloorPlanGraphicsView(QGraphicsScene * scene, QWidget * parent = 0);
~FloorPlanGraphicsView();

void setFloorPlan(const QPixmap & image);
void setIndicator(const QImage & image);

static const int IndicatorType = QGraphicsItem::UserType + 1;
static const int BackgroundType = QGraphicsItem::UserType + 2;

protected:
virtual void resizeEvent(QResizeEvent *);
virtual void mouseDoubleClickEvent(QMouseEvent *event);

private:
void init();
void placeIndicator(const QPointF & point);
void removeIndicator(const QPointF & point);
QGraphicsScene *canvas;
QImage m_indicator;

};

class ImageItem: public QGraphicsRectItem
{
public:
ImageItem( QImage img );

int type() const { return FloorPlanGraphicsView::IndicatorType; }
protected:
void paint( QPainter *, const QStyleOptionGraphicsItem *option, QWidget *widget );
private:
QImage image;
QPixmap pixmap;
};

class BackgroundItem: public QGraphicsPixmapItem
{
public:
BackgroundItem(const QPixmap &pixmap);

virtual int type() const { return FloorPlanGraphicsView::BackgroundType; }
QPixmap getOriginalPixmap();
private:
QPixmap myOriginalPixmap;
};

norobro
30th November 2011, 19:21
I don't think qgraphicsitem_cast will work the way you are using it.

Check your pointer in debug mode:
BackgroundItem *myBackItem = qgraphicsitem_cast<BackgroundItem*>(graphicItems.at(i));
Q_ASSERT(myBackItem);

Try static_cast instead.

shock
30th November 2011, 20:01
I changed the stuff a little bit and got another error facing the same problem as it seems ... as found out that the qgraphicsitem_cast isn't working i wanted to reply here -> then i saw your reply ;)

Anyways .. you're absolutely right.. and static_cast works as i want it to work... (in my new case - i will reconstruct the old one with the old files from SVN)

Could you give me an explanation why "qgraphicsitem_cast" is not working as i expected? Is that my fault or what's wrong here?

norobro
30th November 2011, 22:22
I'm not sure what the advantage of qgraphicsitem_cast is. Maybe someone can enlighten us.

Anyway, here's the source code for qgraphicsitem_cast from qgraphicsitem.h (http://qt.gitorious.org/qt/qt/blobs/4.7/src/gui/graphicsview/qgraphicsitem.h#line1139):
template <class T> inline T qgraphicsitem_cast(QGraphicsItem *item)
{
return int(static_cast<T>(0)->Type) == int(QGraphicsItem::Type)
|| (item && int(static_cast<T>(0)->Type) == item->type()) ? static_cast<T>(item) : 0;
}Since you don't have "Type" defined in your BackgroundItem class, int(static_cast<BackgroundItem *>(0)->Type) returns 7 which is the parent Type (QGraphicsPixmapItem).
Thus:
The first part of the return statement above becomes: 7==1 which is false;
The conditional operator expression (true && 7 == 65538) is false;
Therefore zero is returned and you end up with a null pointer.

Hope this makes sense.

shock
1st December 2011, 16:24
Hmm what you said makes sense but i do NOT get the sense of that graphicsitem_cast .. looks complete senseless ...



template <class T> inline T qgraphicsitem_cast(QGraphicsItem *item)
{
return int(static_cast<T>(0)->Type) == int(QGraphicsItem::Type)
|| (item && int(static_cast<T>(0)->Type) == item->type()) ? static_cast<T>(item) : 0;
}


I do not really get that part: "int(static_cast<T>(0)->Type) == item->type()"
What should that comparison be useful for?