call to QGraphicsScene::update() hangs when compiled with Qt4.6
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 QGraphicsPixmapItemobjects (DroppedItem)
DroppedItem can be selected, resized, and moved.
This is the dropEvent code in the PageItem class
Code:
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");
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
Code:
{
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.
Code:
#include "droppeditem.h"
#include "pageitem.h"
#include <QKeyEvent>
#include <QtDebug>
#include <QTime>
#include <QGraphicsScene>
#include <QMessageBox>
#include <QPainter>
m_originalPixmap(pixmap),
m_imageWidth(m_originalPixmap.width())
{
// set position with scene position.
setPos(scenePos);
setZValue(0.9);
// make the item selectable, movable & focusable
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
}
}
void DroppedItem::zoom(int value)
{
m_currentValue = value;
update(this->boundingRect().toRect());
}
{
if (event->button() != Qt::LeftButton)
{
event->ignore();
return;
}
checkBoundary(event->pos().toPoint(), true);
if(m_tweakingpart != "")
m_tweaking = true;
}
{
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
{
}
}
{
m_tweaking = false ;
m_tweakingpart = "" ;
setCursor
(QCursor(Qt
::OpenHandCursor));
checkBoundary(pt.x(), pt.y());
}
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 );
}
}
}
{
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();
}
QImage DroppedItem
::getScaledImage() {
qreal w = (m_currentValue/100.0) * m_originalPixmap.width();
qreal h = (m_currentValue/100.0) * m_originalPixmap.height();
image = m_originalImage.scaledToWidth(w, Qt::SmoothTransformation);
return image;
}
Re: call to QGraphicsScene::update() hangs when compiled with Qt4.6
Have you set a breakpoint to see if calling scene()->update() from within the DroppedItem::paint() method isn't resulting in an infinite loop?
Re: call to QGraphicsScene::update() hangs when compiled with Qt4.6
setting a breakpoint where?
thanks
Re: call to QGraphicsScene::update() hangs when compiled with Qt4.6
What sense does it make to update a scene from a painting routine? To me it seems you should just add a call to prepareGeometryChange() at the end of your DroppedItem::zoom() method instead of the call to update() there.
Re: call to QGraphicsScene::update() hangs when compiled with Qt4.6
Good day Wysota
I've done that, it now does not hang, and it updates correctly, but I have one issue that shows with this solution
When I change the size of the dropped item, it changes, and resizes correctly. but then, the new boundaries are not detected by mouse events, for example, if the original rect was 50X50, and after resizing it became 100X100, the mouseMoveEvent, mousePressEvent, mouseReleaseEvent and mouseDoubleClickEvent will only detect area within the old boundaries, even it does shows correctly.
even if the mouse if over the new area, the mouse pointer belongs to the parent item (PageItem).
Any suggestions?
Thanks
Re: call to QGraphicsScene::update() hangs when compiled with Qt4.6
Quote:
Originally Posted by
yazwas
When I change the size of the dropped item, it changes, and resizes correctly. but then, the new boundaries are not detected by mouse events, for example, if the original rect was 50X50, and after resizing it became 100X100, the mouseMoveEvent, mousePressEvent, mouseReleaseEvent and mouseDoubleClickEvent will only detect area within the old boundaries, even it does shows correctly.
even if the mouse if over the new area, the mouse pointer belongs to the parent item (PageItem).
Does your implementation of boundingRect() reflect those changes properly? How did you implement it?
Re: call to QGraphicsScene::update() hangs when compiled with Qt4.6
Quote:
Originally Posted by
wysota
Does your implementation of boundingRect() reflect those changes properly? How did you implement it?
Hi
This is how I implemented it, and also you can see the full source code in the original posting above
Code:
QRectF DroppedItem
::boundingRect() const {
qreal w = (m_currentValue/100.0) * m_originalPixmap.width();
qreal h = (m_currentValue/100.0) * m_originalPixmap.height();
}
regards,
Re: call to QGraphicsScene::update() hangs when compiled with Qt4.6
And where are you calling prepareGeometryChange()?
Re: call to QGraphicsScene::update() hangs when compiled with Qt4.6
Quote:
Originally Posted by
wysota
And where are you calling prepareGeometryChange()?
As you suggested, I used it in the zoom function instead of call to update. I've also added it to mouseMoveEvent function, but that also did not change anything.
any suggestions?
thanks
Re: call to QGraphicsScene::update() hangs when compiled with Qt4.6
Everything should work fine then. If it doesn't then apparently your mouseMoveEvent() is incorrectly implemented.
Re: call to QGraphicsScene::update() hangs when compiled with Qt4.6
Quote:
Originally Posted by
wysota
Everything should work fine then. If it doesn't then apparently your mouseMoveEvent() is incorrectly implemented.
can you look at the code posted earlier (in the first post), the logic behind it is as follow
on mousePressEvent(), I check for boundary, if its on the borders, then moseMoveEvent() updates the rectangle
my problem is even the rectangle is resized, but the mouse over the new area, will remain show the mouse cursor that belongs to the pageItem object
regards
Re: call to QGraphicsScene::update() hangs when compiled with Qt4.6
Your logic is too complicated. It's much easier to do this in the scene and using transformation system built into the GraphicsView architecture.
There is some flaw in my code but nevertheles it works most of the time so it's something to base your solution upon:
Code:
#include <QtGui>
public:
Scene() {
activeItem = 0;
}
protected:
activeItem = itemAt(me->scenePos());
if(activeItem) {
QRectF sR
= activeItem
->sceneBoundingRect
();
if(me->pos().x() < sR.left()+10
|| me->pos().x() > sR.right()-10
|| me->pos().y() < sR.top()+10
|| me->pos().y() > sR.bottom()-10)
{
} else activeItem = 0;
}
}
activeItem = 0;
}
if(activeItem) {
QPointF lastScPos
= event
->lastScenePos
();
QRectF sR
= activeItem
->sceneBoundingRect
();
//qreal aspectRatio = sR.width()/sR.height();
qreal zoomLevel = 1.0;
if(qAbs(lastScPos.x()-scPos.x()) > qAbs(lastScPos.y()-scPos.y())) {
// width is leading the transform
if(lastScPos.x() < sR.center().x()) {
newRect.setLeft(scPos.x());
} else if(lastScPos.x() > sR.center().x()) {
newRect.setRight(scPos.x());
}
zoomLevel = newRect.width()/sR.width();
} else {
// height is leading the transform
if(lastScPos.y() < sR.center().y()) {
newRect.setTop(scPos.y());
} else if(lastScPos.y() > sR.center().y()) {
newRect.setBottom(scPos.y());
}
zoomLevel = newRect.height()/sR.height();
}
activeItem->scale(zoomLevel, zoomLevel);
activeItem->setPos(activeItem->mapFromScene(newRect.topLeft()));
}
private:
};
int main(int argc, char **argv){
Scene scene;
view.setScene(&scene);
view.show();
scene.
addPixmap(QPixmap("/usr/share/wallpapers/Midnight_in_Karelia/contents/screnshot.jpg"));
return app.exec();
}