[SOLVED]Crash on ensureVisible ?
-
I have a problem with ensureVisible and I didn't find an answer why this thing behaves like that. So, I have a view, this view is displaying on a scene where I added a movable rect item, and I'm trying to do some auto-scrolling when I'm moving the item but when the view has his height smaller than a value the app crashes. I did a small code example to show the behavior:
#ifndef TESTVIEW_H
#define TESTVIEW_H#include<QGraphicsView>
#include<QGraphicsScene>
#include<QGraphicsRectItem>class MyView : public QGraphicsView
{
QGraphicsScene* myScene;public:
MyView();
};class MyItem : public QGraphicsRectItem
{
public:
MyItem();
//events
QVariant itemChange( GraphicsItemChange change, const QVariant &value );
};#endif // TESTVIEW_H
#include "testview.h"
MyView::MyView() : QGraphicsView()
{
myScene = new QGraphicsScene;
setFixedHeight( 100 );
setScene( myScene );
myScene->setSceneRect( 0, 0, 2000, 2000 );
MyItem* item = new MyItem;
myScene->addItem( item );
}MyItem::MyItem() : QGraphicsRectItem()
{
setRect( 0,0, 50, 50 );
setFlag(ItemSendsGeometryChanges,true);
setFlag(ItemIsMovable, true );
setZValue( 4 );
}QVariant MyItem::itemChange(GraphicsItemChange change, const QVariant &value)
{
if( change == ItemPositionChange )
{
scene()->views()[0]->ensureVisible( this );
}
return QGraphicsRectItem::itemChange( change, value );
}#include<QApplication>
#include"testview.h"int main( int argc, char* argv[] )
{
QApplication app( argc, argv );MyView* testView = new MyView; testView->show(); return app.exec()
}@
When I'm removing this line : setFixedHeight( 100 ); the view will have a bigger height and it will work as it should but in my app I really need a smaller view and that is not a solution for me. Or maybe I'm doing something wrong in my code. Please take a look and let me know.
Thanks!
-
The inferior stopped because it received a signal from the OS. Signal name: SIGSEGV, Signal Meaning : Segmentation fault . The call stack looks like this:
0 QScopedPointer<QObjectData, QScopedPointerDeleter<QObjectData> >::operator-> qscopedpointer.h 112 0x00f18c23
1 QObject::parent qobject.h 250 0x00f4b39c
2 QWidget::parentWidget qwidget.h 1022 0x00f51865
3 QWidget::window qwidget.cpp 4182 0x007ea2b1
4 QWidgetPrivate::scrollRect qbackingstore.cpp 980 0x00973662
5 QWidgetPrivate::scroll_sys qwidget_win.cpp 1605 0x00825a3c
6 QWidget::scroll qwidget.cpp 10138 0x007f7222
7 QGraphicsView::scrollContentsBy qgraphicsview.cpp 3601 0x00d6dd44
8 QAbstractScrollAreaPrivate::_q_vslide qabstractscrollarea.cpp 1319 0x00bfc246
9 QAbstractScrollArea::qt_metacall moc_qabstractscrollarea.cpp 85 0x00bfc6bf
10 QGraphicsView::qt_metacall moc_qgraphicsview.cpp 152 0x00d6e96a
11 QMetaObject::metacall qmetaobject.cpp 237 0x6a20445c
12 QMetaObject::activate qobject.cpp 3272 0x6a214bbe
13 QAbstractSlider::valueChanged moc_qabstractslider.cpp 182 0x00db32fa
14 QAbstractSlider::setValue qabstractslider.cpp 543 0x00b24ee4
15 QGraphicsView::ensureVisible qgraphicsview.cpp 1905 0x00d672cc
16 QGraphicsView::ensureVisible qgraphicsview.cpp 1930 0x00d6730d
17 MyItem::itemChange testview.cpp 28 0x0040196c
18 QGraphicsItem::setPos qgraphicsitem.cpp 3678 0x00d223ba
19 QGraphicsItem::mouseMoveEvent qgraphicsitem.cpp 7126 0x00d2af36
20 QGraphicsItem::sceneEvent qgraphicsitem.cpp 6663 0x00d29aab
... <More>My guess is that when the ensureVisible is called, itemChange is called so we're entering into an infinite loop( don't know if it's a correct behavior ), but why it's working on views with higher height?
Thanks! -
I think your code triggers a corner case where ensureVisible() implicitly causes QGraphicsItem::setPos() to be called. This in turn causes a new itemChange event. The Qt Documentation states that method calls that affect the item state should be avoided inside itemChange() since they might trigger endless recursion:
http://doc.qt.nokia.com/4.7/qgraphicsitem.html#GraphicsItemChange-enum
The following code should work:
@
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsRectItem>
#include <QApplication>
#include <QMouseEvent>class MyView : public QGraphicsView
{QGraphicsScene* myScene;
public:
MyView();protected:
void mouseMoveEvent(QMouseEvent* event);};
class MyItem : public QGraphicsRectItem
{
public:
MyItem();};
MyView::MyView() : QGraphicsView()
{
myScene = new QGraphicsScene;
setFixedHeight( 100 );
setScene( myScene );
myScene->setSceneRect( 0, 0, 2000, 2000 );
MyItem* item = new MyItem;
myScene->addItem( item );
}void MyView::mouseMoveEvent(QMouseEvent* event)
{QGraphicsView::mouseMoveEvent(event);
QGraphicsItem* item = itemAt(event->pos());
if (item) {
ensureVisible(item);
}}
MyItem::MyItem() : QGraphicsRectItem()
{
setRect( 0,0, 50, 50 );
setFlag(ItemSendsGeometryChanges,true);
setFlag(ItemIsMovable, true );
setZValue( 4 );
}int main( int argc, char* argv[])
{
QApplication app( argc, argv );MyView* testView = new MyView;
testView->show();return app.exec();
}
@This is of course no perfect solution (if such a thing exists, anyway) but works well enough to illustrate a possible workaround.