yazwas
5th March 2011, 22:29
Good day
I have an application that is running fine on Qt 4.5 under both Windows and Linux, but when trying to compile it with Qt 4.6 or later, it hangs when calling QGraphicsScene::update() function inside grandchild object
The hierarchy of the design as follow
QGraphicsScene (DrawerScene), which has one object of type QGraphicsRectItem (PageItem)
in the pageItem we can add multiple QGraphicsPixmapItem objects (DroppedItem)
DroppedItem can be selected, resized, and moved.
This is the dropEvent code in the PageItem class
void PageItem::dropEvent(QGraphicsSceneDragDropEvent * event)
{
// verify that we drop an image.
if (event->mimeData()->hasImage())
{
QPointF pt = event->pos(); //QPointF pt = mapToItem(this, event->pos());
QByteArray byteArray = event->mimeData()->data("image/jpg");
QPixmap pixmap = QPixmap::fromImage( QImage::fromData(byteArray, "jpg") );
new DroppedItem(pixmap, pt, 1.0, this);
}
}
in the DroppedItem class, the hang happens in the paint function when calling the update function of the scene object, as in the code below
void DroppedItem::paint(QPainter *painter, const QStyleOptionGraphicsItem
*option, QWidget *widget)
{
painter->drawImage(boundingRect().toRect(),getScaledImage() );
//the line below works OK for Qt 4.5, but hangs (on Linux) for Qt 4.6, 4.7)
//the line below is needed to update the scene so that it reflects this item is
//being resized.
//I've tried to comment it, and add it to the zoom function (see full code below),
//but it does not reflect the same behavior.
scene()->update(scene()->itemsBoundingRect());
}
Below is the full source code for the DroppedItem.cpp file, I can provide any other info if needed.
#include "droppeditem.h"
#include "pageitem.h"
#include <QKeyEvent>
#include <QtDebug>
#include <QTime>
#include <QGraphicsScene>
#include <QMessageBox>
#include <QPainter>
DroppedItem::DroppedItem(const QPixmap & pixmap, const QPointF & scenePos, qreal perc, QGraphicsItem * parent /*=0*/) :
QGraphicsPixmapItem(pixmap, parent),
m_originalPixmap(pixmap),
m_imageWidth(m_originalPixmap.width())
{
// set position with scene position.
setPos(scenePos);
setZValue(0.9);
// make the item selectable, movable & focusable
setFlag(QGraphicsItem::ItemIsSelectable, true);
setFlag(QGraphicsItem::ItemIsMovable, true);
setFlag(QGraphicsItem::ItemIsFocusable,true);
m_pageItem = static_cast<PageItem*> (parentItem());
setPixmap(m_originalPixmap);
m_originalImage = m_originalPixmap.toImage();
}
DroppedItem::~DroppedItem()
{
}
int DroppedItem::type() const
{
return Type;
}
void DroppedItem::keyPressEvent(QKeyEvent * event)
{
if (event->key() == Qt::Key_Delete && isSelected())
{
// remove item when key press event is Suppr.
scene()->removeItem(this);
return;
}
else
{
//check if the new position is within the boundary of the page
QGraphicsPixmapItem::keyPressEvent(event);
}
}
void DroppedItem::zoom(int value)
{
m_currentValue = value;
update(this->boundingRect().toRect());
}
void DroppedItem::mousePressEvent(QGraphicsSceneMouseEv ent *event)
{
if (event->button() != Qt::LeftButton)
{
event->ignore();
return;
}
checkBoundary(event->pos().toPoint(), true);
if(m_tweakingpart != "")
m_tweaking = true;
QGraphicsPixmapItem::mousePressEvent(event);
}
void DroppedItem::mouseMoveEvent(QGraphicsSceneMouseEve nt *event)
{
if(m_tweaking)
{
QPoint pt = event->pos().toPoint();
m_rectangle = this->boundingRect().toRect();
qreal value = 1.0;
if ( m_tweakingpart == "bottomRight" ) { m_rectangle . setBottomRight ( pt ) ; value = static_cast<qreal> (m_rectangle.height() / (m_originalPixmap.height()*1.0) );}
else if ( m_tweakingpart == "bottom" ) { m_rectangle . setBottom ( pt . y () ) ; value = static_cast<qreal> (m_rectangle.height() / (m_originalPixmap.height()*1.0) );}
else if ( m_tweakingpart == "right" ) { m_rectangle . setRight ( pt . x () ) ; value = static_cast<qreal> (m_rectangle.width() / (m_originalPixmap.width() *1.0) );}
zoom(value*100);
}
else
{
QGraphicsPixmapItem::mouseMoveEvent(event);
}
}
void DroppedItem::mouseReleaseEvent(QGraphicsSceneMouse Event *event)
{
m_tweaking = false ;
m_tweakingpart = "" ;
setCursor(QCursor(Qt::OpenHandCursor));
QPointF pt = pos();
checkBoundary(pt.x(), pt.y());
QGraphicsPixmapItem::mouseReleaseEvent(event);
}
void DroppedItem::checkBoundary(QPoint pt, bool t)
{
m_rectangle = this->boundingRect().toRect();
if ( m_rectangle.isValid() )
{
QPoint m_tl = m_rectangle.topLeft();
QPoint m_tr = m_rectangle.topRight();
QPoint m_bl = m_rectangle.bottomLeft();
QPoint m_br = m_rectangle.bottomRight();
const QPoint off(20, 20), offx(20, -20), offy(-20, 20);
if( QRect( m_br-off, m_br+off).contains(pt) )
{
if (t)
m_tweakingpart = "bottomRight" ;
this->setCursor( Qt::SizeFDiagCursor );
}
else if( QRect( m_bl+offx, m_br-offx ).contains(pt) )
{
if (t)
m_tweakingpart = "bottom";
this->setCursor( Qt::SizeVerCursor ) ;
}
else if( QRect( m_tr+offy, m_br-offy ).contains(pt) )
{
if (t)
m_tweakingpart = "right";
this->setCursor( Qt::SizeHorCursor );
}
}
}
void DroppedItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->drawImage(boundingRect().toRect(),getScaledImage() );
//this causes the program to hang when compiled with Qt >= 4.6
//(I checked only on Linux, but I think it will hang on Windows as well)
scene()->update(scene()->itemsBoundingRect());
}
QRectF DroppedItem::boundingRect() const
{
qreal w = (m_currentValue/100.0) * m_originalPixmap.width();
qreal h = (m_currentValue/100.0) * m_originalPixmap.height();
return QRectF(QPointF(0,0), QPointF(w, h));
}
QImage DroppedItem::getScaledImage()
{
qreal w = (m_currentValue/100.0) * m_originalPixmap.width();
qreal h = (m_currentValue/100.0) * m_originalPixmap.height();
QSizeF size(w, h);
QImage image(size.toSize(), QImage::Format_RGB888);
image = m_originalImage.scaledToWidth(w, Qt::SmoothTransformation);
return image;
}
I have an application that is running fine on Qt 4.5 under both Windows and Linux, but when trying to compile it with Qt 4.6 or later, it hangs when calling QGraphicsScene::update() function inside grandchild object
The hierarchy of the design as follow
QGraphicsScene (DrawerScene), which has one object of type QGraphicsRectItem (PageItem)
in the pageItem we can add multiple QGraphicsPixmapItem objects (DroppedItem)
DroppedItem can be selected, resized, and moved.
This is the dropEvent code in the PageItem class
void PageItem::dropEvent(QGraphicsSceneDragDropEvent * event)
{
// verify that we drop an image.
if (event->mimeData()->hasImage())
{
QPointF pt = event->pos(); //QPointF pt = mapToItem(this, event->pos());
QByteArray byteArray = event->mimeData()->data("image/jpg");
QPixmap pixmap = QPixmap::fromImage( QImage::fromData(byteArray, "jpg") );
new DroppedItem(pixmap, pt, 1.0, this);
}
}
in the DroppedItem class, the hang happens in the paint function when calling the update function of the scene object, as in the code below
void DroppedItem::paint(QPainter *painter, const QStyleOptionGraphicsItem
*option, QWidget *widget)
{
painter->drawImage(boundingRect().toRect(),getScaledImage() );
//the line below works OK for Qt 4.5, but hangs (on Linux) for Qt 4.6, 4.7)
//the line below is needed to update the scene so that it reflects this item is
//being resized.
//I've tried to comment it, and add it to the zoom function (see full code below),
//but it does not reflect the same behavior.
scene()->update(scene()->itemsBoundingRect());
}
Below is the full source code for the DroppedItem.cpp file, I can provide any other info if needed.
#include "droppeditem.h"
#include "pageitem.h"
#include <QKeyEvent>
#include <QtDebug>
#include <QTime>
#include <QGraphicsScene>
#include <QMessageBox>
#include <QPainter>
DroppedItem::DroppedItem(const QPixmap & pixmap, const QPointF & scenePos, qreal perc, QGraphicsItem * parent /*=0*/) :
QGraphicsPixmapItem(pixmap, parent),
m_originalPixmap(pixmap),
m_imageWidth(m_originalPixmap.width())
{
// set position with scene position.
setPos(scenePos);
setZValue(0.9);
// make the item selectable, movable & focusable
setFlag(QGraphicsItem::ItemIsSelectable, true);
setFlag(QGraphicsItem::ItemIsMovable, true);
setFlag(QGraphicsItem::ItemIsFocusable,true);
m_pageItem = static_cast<PageItem*> (parentItem());
setPixmap(m_originalPixmap);
m_originalImage = m_originalPixmap.toImage();
}
DroppedItem::~DroppedItem()
{
}
int DroppedItem::type() const
{
return Type;
}
void DroppedItem::keyPressEvent(QKeyEvent * event)
{
if (event->key() == Qt::Key_Delete && isSelected())
{
// remove item when key press event is Suppr.
scene()->removeItem(this);
return;
}
else
{
//check if the new position is within the boundary of the page
QGraphicsPixmapItem::keyPressEvent(event);
}
}
void DroppedItem::zoom(int value)
{
m_currentValue = value;
update(this->boundingRect().toRect());
}
void DroppedItem::mousePressEvent(QGraphicsSceneMouseEv ent *event)
{
if (event->button() != Qt::LeftButton)
{
event->ignore();
return;
}
checkBoundary(event->pos().toPoint(), true);
if(m_tweakingpart != "")
m_tweaking = true;
QGraphicsPixmapItem::mousePressEvent(event);
}
void DroppedItem::mouseMoveEvent(QGraphicsSceneMouseEve nt *event)
{
if(m_tweaking)
{
QPoint pt = event->pos().toPoint();
m_rectangle = this->boundingRect().toRect();
qreal value = 1.0;
if ( m_tweakingpart == "bottomRight" ) { m_rectangle . setBottomRight ( pt ) ; value = static_cast<qreal> (m_rectangle.height() / (m_originalPixmap.height()*1.0) );}
else if ( m_tweakingpart == "bottom" ) { m_rectangle . setBottom ( pt . y () ) ; value = static_cast<qreal> (m_rectangle.height() / (m_originalPixmap.height()*1.0) );}
else if ( m_tweakingpart == "right" ) { m_rectangle . setRight ( pt . x () ) ; value = static_cast<qreal> (m_rectangle.width() / (m_originalPixmap.width() *1.0) );}
zoom(value*100);
}
else
{
QGraphicsPixmapItem::mouseMoveEvent(event);
}
}
void DroppedItem::mouseReleaseEvent(QGraphicsSceneMouse Event *event)
{
m_tweaking = false ;
m_tweakingpart = "" ;
setCursor(QCursor(Qt::OpenHandCursor));
QPointF pt = pos();
checkBoundary(pt.x(), pt.y());
QGraphicsPixmapItem::mouseReleaseEvent(event);
}
void DroppedItem::checkBoundary(QPoint pt, bool t)
{
m_rectangle = this->boundingRect().toRect();
if ( m_rectangle.isValid() )
{
QPoint m_tl = m_rectangle.topLeft();
QPoint m_tr = m_rectangle.topRight();
QPoint m_bl = m_rectangle.bottomLeft();
QPoint m_br = m_rectangle.bottomRight();
const QPoint off(20, 20), offx(20, -20), offy(-20, 20);
if( QRect( m_br-off, m_br+off).contains(pt) )
{
if (t)
m_tweakingpart = "bottomRight" ;
this->setCursor( Qt::SizeFDiagCursor );
}
else if( QRect( m_bl+offx, m_br-offx ).contains(pt) )
{
if (t)
m_tweakingpart = "bottom";
this->setCursor( Qt::SizeVerCursor ) ;
}
else if( QRect( m_tr+offy, m_br-offy ).contains(pt) )
{
if (t)
m_tweakingpart = "right";
this->setCursor( Qt::SizeHorCursor );
}
}
}
void DroppedItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->drawImage(boundingRect().toRect(),getScaledImage() );
//this causes the program to hang when compiled with Qt >= 4.6
//(I checked only on Linux, but I think it will hang on Windows as well)
scene()->update(scene()->itemsBoundingRect());
}
QRectF DroppedItem::boundingRect() const
{
qreal w = (m_currentValue/100.0) * m_originalPixmap.width();
qreal h = (m_currentValue/100.0) * m_originalPixmap.height();
return QRectF(QPointF(0,0), QPointF(w, h));
}
QImage DroppedItem::getScaledImage()
{
qreal w = (m_currentValue/100.0) * m_originalPixmap.width();
qreal h = (m_currentValue/100.0) * m_originalPixmap.height();
QSizeF size(w, h);
QImage image(size.toSize(), QImage::Format_RGB888);
image = m_originalImage.scaledToWidth(w, Qt::SmoothTransformation);
return image;
}