Reputation: 717
The following program paints a red background. Pressing the left mouse button paints a white rectangle onto it. The rectangle has a child rectangle and a QGraphicsDropShadowEffect
. (QGraphicsOpacityEffect
and QGraphicsColorizeEffect
also lead to the problem, but less frequently.)
Pressing the right mouse button removes the white rectangle.
Sometimes when removing the rectangle it causes a segmentation fault.
This does not happen if the QGraphicsDropShadowEffect
is not applied. It also does not happen when there either is no child item in MyRect
or the background is ommited.
(When searching for this issue, I found several hints that a segfault like this could be related to changing the boundingRect()
of an item without calling prepareGeometryChange()
.)
I am really at a loss here. This is part of a bigger project and I boiled it down to the following example:
Main.cc:
#include<QApplication>
#include<QGraphicsView>
#include<QGraphicsScene>
#include<QGraphicsSceneMouseEvent>
#include<QGraphicsRectItem>
#include<QGraphicsDropShadowEffect>
#include<QScreen>
class MyRect: public QGraphicsRectItem
{
public:
MyRect(QGraphicsItem* parent = nullptr):
QGraphicsRectItem{QRectF{0.0f, 0.0f, 100.0f, 100.0f}, parent}
{
setPen(QPen{Qt::white});
setBrush(QBrush{Qt::white, Qt::SolidPattern});
my_child_=new QGraphicsRectItem{this};
}
private:
QGraphicsRectItem* my_child_=nullptr;
};
class MyScene: public QGraphicsScene
{
public:
MyScene()
{
background_=new QGraphicsRectItem{0.0f, 0.0f, 500.0f, 500.0f};
background_->setPen(QPen{Qt::white});
background_->setBrush(QBrush{Qt::red, Qt::SolidPattern});
addItem(background_);
}
void mouseReleaseEvent(QGraphicsSceneMouseEvent* me) override
{
if (me->button()==Qt::LeftButton)
{
if (my_rect_==nullptr)
{
my_rect_=new MyRect{};
shadow_=new QGraphicsDropShadowEffect{};
shadow_->setBlurRadius(15.0f);
my_rect_->setGraphicsEffect(shadow_);
addItem(my_rect_);
my_rect_->setPos(me->scenePos());
}
}
else if (me->button()==Qt::RightButton)
{
if (my_rect_!=nullptr)
{
removeItem(my_rect_);
my_rect_->setGraphicsEffect(0);
shadow_=nullptr;
delete my_rect_;
my_rect_=nullptr;
}
}
else
{
QGraphicsScene::mouseReleaseEvent(me);
}
}
private:
QGraphicsRectItem* background_=nullptr;
MyRect* my_rect_=nullptr;
QGraphicsDropShadowEffect* shadow_=nullptr;
};
int
main(int argc, char** argv)
{
QApplication qapp{argc, argv};
QGraphicsView view;
MyScene scene;
QRect rect=QGuiApplication::primaryScreen()->geometry();
scene.setSceneRect(0.0f, 0.0f, rect.width(), rect.height());
view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
view.setFrameShape(QFrame::NoFrame);
view.setBackgroundBrush(QBrush(Qt::black, Qt::SolidPattern));
view.setScene(&scene);
view.showFullScreen();
return qapp.exec();
}
Compiler call:
g++ --std=c++14 -fPIC -Wall -Woverloaded-virtual -Werror -pedantic -g -O0 -fPIC -I/usr/include/x86_64-linux-gnu/qt5/QtGui -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtCore -I/usr/include/x86_64-linux-gnu/qt5 -o test Main.cc -lQt5Gui -lQt5Core -lQt5Widgets
Backtrace:
#0 0x0000555555a9a840 in ?? ()
#1 0x00007ffff71e017c in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#2 0x00007ffff71e0a3a in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#3 0x00007ffff720289a in QGraphicsView::paintEvent(QPaintEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#4 0x00007ffff6f10278 in QWidget::event(QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#5 0x00007ffff6ff89fe in QFrame::event(QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#6 0x00007ffff72013ab in QGraphicsView::viewportEvent(QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#7 0x00007ffff7650701 in QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject*, QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#8 0x00007ffff6ec8b65 in QApplicationPrivate::notify_helper(QObject*, QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#9 0x00007ffff6ed0341 in QApplication::notify(QObject*, QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#10 0x00007ffff76509a0 in QCoreApplication::notifyInternal2(QObject*, QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#11 0x00007ffff6f08fda in QWidgetPrivate::sendPaintEvent(QRegion const&) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#12 0x00007ffff6f09646 in QWidgetPrivate::drawWidget(QPaintDevice*, QRegion const&, QPoint const&, int, QPainter*, QWidgetBackingStore*) ()
from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#13 0x00007ffff6ed8f1e in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#14 0x00007ffff6ed9147 in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#15 0x00007ffff6ef7f8f in QWidgetPrivate::syncBackingStore() () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#16 0x00007ffff6f10348 in QWidget::event(QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#17 0x00007ffff6ff89fe in QFrame::event(QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#18 0x00007ffff7081de3 in QAbstractScrollArea::event(QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#19 0x00007ffff6ec8b8c in QApplicationPrivate::notify_helper(QObject*, QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#20 0x00007ffff6ed0341 in QApplication::notify(QObject*, QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#21 0x00007ffff76509a0 in QCoreApplication::notifyInternal2(QObject*, QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#22 0x00007ffff765312d in QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#23 0x00007ffff71d2a22 in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#24 0x00007ffff71d8299 in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#25 0x00007ffff767d459 in QObject::event(QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#26 0x00007ffff71e4e6b in QGraphicsScene::event(QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#27 0x00007ffff6ec8b8c in QApplicationPrivate::notify_helper(QObject*, QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#28 0x00007ffff6ed0341 in QApplication::notify(QObject*, QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#29 0x00007ffff76509a0 in QCoreApplication::notifyInternal2(QObject*, QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#30 0x00007ffff765312d in QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#31 0x00007ffff76a4c03 in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#32 0x00007ffff446f7f7 in g_main_context_dispatch () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#33 0x00007ffff446fa60 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#34 0x00007ffff446fb0c in g_main_context_iteration () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#35 0x00007ffff76a500f in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#36 0x00007ffff764e98a in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#37 0x00007ffff76570fc in QCoreApplication::exec() () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#38 0x000055555555768b in main (argc=1, argv=0x7fffffffe5b8) at Main.cc:89
EDIT: I rewritten the code example for better readability.
Upvotes: 2
Views: 1210
Reputation: 717
As I was educated on on the Qt forums this is not expected behaviour and might be a bug in Qt.
The best workaround is to call QGraphicsItem::prepareGeometryChange()
on my_rect_
before removing it from the scene. This might be done be exposing the protected prepareGeometryChange()
or by calling it inside ~MyRect()
and then simply deleting my_rect_
without calling QGraphicsScene::removeItem()
. ~QGraphicsItem()
, which of course is called after ~MyRect()
, will automatically remove the item from the scene.
Upvotes: 1