PDA

View Full Version : How to iterate through GraphicsScene items using items()



MercyYuen
9th October 2012, 23:39
I would like my QGraphicsScene to go through the GraphicItems that are on the screen, check some of the properties and then change the GraphicItems' color accordingly.

In my QGraphicsScene class I have this code fragment. I expect it to only go through the foreach loop ONCE because there is only one item on the screen right now. But instead, it tries to go through twice. This is a problem because I get a segmentation fault when it tries to go through the loop the second time.

Ideas??


foreach(QGraphicsItem *item, items())
{
DiagramItem *zone = qgraphicsitem_cast<DiagramItem *>(item);
myPenColor = zone->zoneColor;
zone->setPen(myPenColor);
}

Here is my complete class for context:



#include <QtGui>
#include <sstream>
#include <QGraphicsItem>

#include "scribblearea.h"
#include "diagramitem.h"

QVector <QPoint> polygonPoints(4);
QPolygon polygon(4);


QPolygon ScribbleArea::getPoly()
{
return polygon;
}

//! [0]
ScribbleArea::ScribbleArea(QWidget *parent)
: QGraphicsScene(parent)
{
//setAttribute(Qt::WA_StaticContents);
modified = false;
scribbling = false;
myPenWidth = 1;
myPenColor = Qt::blue;
newZone = false;
polyIndex = 0;
zoneCount = 0;


QPixmap pix;
if (!pix.load( ":/images/iterislogo.jpg" ))
{
qWarning("Failed to load iterislogo.png");
}
else
{
QGraphicsPixmapItem *item = this->addPixmap(pix);
item->setPos(0,500);
}
}
//! [0]

//! [1]
bool ScribbleArea::openImage(const QString &fileName)
//! [1] //! [2]
{

return true;
}
//! [2]

//! [3]
bool ScribbleArea::saveImage(const QString &fileName, const char *fileFormat)
//! [3] //! [4]
{

return false;
}
//! [4]

//! [5]
void ScribbleArea::setPenColor(const QColor &newColor)
//! [5] //! [6]
{
myPenColor = newColor;
}
//! [6]

//! [7]
void ScribbleArea::setPenWidth(int newWidth)
//! [7] //! [8]
{
myPenWidth = newWidth;
}
//! [8]

void ScribbleArea::timesUp()
{

//DiagramItem *zone = qgraphicsitem_cast<DiagramItem *>(all);

for (int i = 0; i < zoneCount; i++)
{
foreach(QGraphicsItem *item, items())
{
DiagramItem *zone = qgraphicsitem_cast<DiagramItem *>(item);
myPenColor = zone->zoneColor;
zone->setPen(myPenColor);
}
}



}

void ScribbleArea::activateImage()
//! [9] //! [10]
{
foreach (QGraphicsItem *item, selectedItems()) {
DiagramItem *zone = qgraphicsitem_cast<DiagramItem *>(item);
myPenColor= Qt::red;
zone->setPen(myPenColor);

zone->toggleState();

}
}

void ScribbleArea::deactivateImage()
//! [9] //! [10]
{
foreach (QGraphicsItem *item, selectedItems()) {
DiagramItem *zone = qgraphicsitem_cast<DiagramItem *>(item);
myPenColor = Qt::blue;
zone->setPen(myPenColor);

zone->toggleState();

}
}

//! [9]
void ScribbleArea::clearImage()
//! [9] //! [10]
{
foreach (QGraphicsItem *item, selectedItems()) {
delete item;
zoneCount--;
}
}
//! [10]
void ScribbleArea::drawZone()
{
newZone = true;
}

//! [11]
void ScribbleArea::mousePressEvent(QGraphicsSceneMouseE vent *event)
//! [11] //! [12]
{
if (event->button() == Qt::LeftButton) {
lastPoint = event->scenePos();
scribbling = true;

if( newZone ) // If drawing a new zone
{
polygon.setPoint(polyIndex++, event->scenePos().x(), event->scenePos().y());

if( polyIndex > 3)
{
newZone = false;


DiagramItem *item;

item = new DiagramItem(this);
item->setPen(myPenColor);
addItem(item);

QPointF details = event->scenePos(); // debug purposes only

polyIndex = 0;
zoneCount++;
}
}
}
QGraphicsScene::mousePressEvent(event);
}

void ScribbleArea::mouseMoveEvent(QGraphicsSceneMouseEv ent *event)
{

QGraphicsScene::mouseMoveEvent(event);
}


//! [14]

//! [15]

//! [18]

//! [19]
void ScribbleArea::resizeImage(QImage *image, const QSize &newSize)
//! [19] //! [20]
{
if (image->size() == newSize)
return;

QImage newImage(newSize, QImage::Format_RGB32);
newImage.fill(qRgb(255, 255, 255));
QPainter painter(&newImage);
painter.drawImage(QPoint(0, 0), *image);
*image = newImage;
}
//! [20]


//! [22]

wysota
10th October 2012, 00:52
Hmmm... because there are two items in the scene?

ChrisW67
10th October 2012, 00:55
There is a difference between "on the screen", the term you use, and "in the scene", which is what you are iterating over. Perhaps you want to look at the QGraphicsView::items() to identify what a particular view is actually showing.

MercyYuen
10th October 2012, 01:52
I'm sorry for using the incorrect vocabulary. I definitely mean "in the scene."

I might be wrong, but I think there is only ONE item in the scene because
1. I only put one polygon item in the scene.
2. I get a Segmentation fault when the code tries to run through the loop a second time on the non-existent item.

thoughts?

ChrisW67
10th October 2012, 02:23
The segmentation fault is a good clue. Why would zone be null or invalid? If the second item is not a DiagramItem, the cast fails, and you try to deference a null pointer as a result. Line 38 of your second listing adds a QGraphicsPixmapItem...

If you are only interested in DiagramItems and there can be other types in the scene then your code should look like:



foreach(QGraphicsItem *item, items())
{
DiagramItem *zone = ggraphicsitem_cast<DiagramItem *>(item);
if (zone)
{
myPenColor = zone->zoneColor;
zone->setPen(myPenColor);
}
}

MercyYuen
10th October 2012, 16:51
thank you! I absolutely forgot about that pixmap item!