Fix pointer mismatch after QList::move() in tooltip example

The tooltip example moves shape items within a QWidget. Shape items are
stored in a QList of objects. When an item is moved, its pointer is
taken from the QList and stored in a member variable. To have the moved
item on the bottom of the list, QList::move() is called. This
operation re-arranges the list objects, and the member variable starts
pointing at a wrong object.

This patch changes the list from a list of objects, to a list of
pointers. Shape items are therefore allocated on the heap.
A destructor is added to free the heap with qDeleteAll.

The example's documentation is adapted accordingly and a snippet for
the destructor is added.

As a drive-by, int is replaced by qsizetype where it was used as an
index of a QList.

Fixes: QTBUG-104781
Pick-to: 6.5 6.2
Change-Id: I9be26fa7954be5f85729d24f166d66980af71801
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
This commit is contained in:
Axel Spoerl 2023-03-22 10:11:11 +01:00 committed by Shawn Rutledge
parent df0b661bfc
commit 585bfe600a
3 changed files with 36 additions and 24 deletions

View File

@ -124,6 +124,10 @@
private \c createShapeItem(), \c initialItemPosition() and \c
initialItemColor() functions.
\snippet widgets/tooltips/sortingbox.cpp 27
In the destructor, we delete all shape items.
\snippet widgets/tooltips/sortingbox.cpp 5
QWidget::event() is the main event handler and receives all the
@ -199,8 +203,9 @@
If an item covers the position, we store a pointer to that item
and the event's position. If several of the shape items cover the
position, we store the pointer to the uppermost item. Finally, we
move the shape item to the end of the list, and make a call to the
QWidget::update() function to make the item appear on top.
move the shape item's pointer to the end of the list, and make
a call to the QWidget::update() function to make the item appear
on top.
The QWidget::update() function does not cause an immediate
repaint; instead it schedules a paint event for processing when Qt
@ -290,10 +295,9 @@
The \c createShapeItem() function creates a single shape item. It
sets the path, tooltip, position and color, using the item's own
functions. In the end, the function appends the new item to the
list of shape items, and calls the QWidget::update() function to
make it appear with the other items within the \c SortingBox
widget.
functions. In the end, the function appends the new item's pointer
to the list of shape items, and calls QWidget::update() to make
it appear with the other items within the \c SortingBox widget.
\snippet widgets/tooltips/sortingbox.cpp 22

View File

@ -59,6 +59,13 @@ SortingBox::SortingBox(QWidget *parent)
}
//! [4]
//! [27]
SortingBox::~SortingBox()
{
qDeleteAll(shapeItems);
}
//! [27]
//! [5]
bool SortingBox::event(QEvent *event)
{
@ -67,7 +74,7 @@ bool SortingBox::event(QEvent *event)
QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
int index = itemAt(helpEvent->pos());
if (index != -1) {
QToolTip::showText(helpEvent->globalPos(), shapeItems[index].toolTip());
QToolTip::showText(helpEvent->globalPos(), shapeItems[index]->toolTip());
} else {
QToolTip::hideText();
event->ignore();
@ -97,13 +104,13 @@ void SortingBox::paintEvent(QPaintEvent * /* event */)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
for (const ShapeItem &shapeItem : std::as_const(shapeItems)) {
for (const ShapeItem *shapeItem : std::as_const(shapeItems)) {
//! [8] //! [9]
painter.translate(shapeItem.position());
painter.translate(shapeItem->position());
//! [9] //! [10]
painter.setBrush(shapeItem.color());
painter.drawPath(shapeItem.path());
painter.translate(-shapeItem.position());
painter.setBrush(shapeItem->color());
painter.drawPath(shapeItem->path());
painter.translate(-shapeItem->position());
}
}
//! [10]
@ -114,7 +121,7 @@ void SortingBox::mousePressEvent(QMouseEvent *event)
if (event->button() == Qt::LeftButton) {
int index = itemAt(event->position().toPoint());
if (index != -1) {
itemInMotion = &shapeItems[index];
itemInMotion = shapeItems[index];
previousPosition = event->position().toPoint();
shapeItems.move(index, shapeItems.size() - 1);
update();
@ -169,11 +176,11 @@ void SortingBox::createNewTriangle()
//! [16]
//! [17]
int SortingBox::itemAt(const QPoint &pos)
qsizetype SortingBox::itemAt(const QPoint &pos)
{
for (int i = shapeItems.size() - 1; i >= 0; --i) {
const ShapeItem &item = shapeItems[i];
if (item.path().contains(pos - item.position()))
for (qsizetype i = shapeItems.size() - 1; i >= 0; --i) {
const ShapeItem *item = shapeItems[i];
if (item->path().contains(pos - item->position()))
return i;
}
return -1;
@ -208,11 +215,11 @@ void SortingBox::createShapeItem(const QPainterPath &path,
const QString &toolTip, const QPoint &pos,
const QColor &color)
{
ShapeItem shapeItem;
shapeItem.setPath(path);
shapeItem.setToolTip(toolTip);
shapeItem.setPosition(pos);
shapeItem.setColor(color);
ShapeItem *shapeItem = new ShapeItem;
shapeItem->setPath(path);
shapeItem->setToolTip(toolTip);
shapeItem->setPosition(pos);
shapeItem->setColor(color);
shapeItems.append(shapeItem);
update();
}

View File

@ -21,6 +21,7 @@ class SortingBox : public QWidget
public:
SortingBox(QWidget *parent = nullptr);
~SortingBox();
protected:
bool event(QEvent *event) override;
@ -41,7 +42,7 @@ private:
int updateButtonGeometry(QToolButton *button, int x, int y);
void createShapeItem(const QPainterPath &path, const QString &toolTip,
const QPoint &pos, const QColor &color);
int itemAt(const QPoint &pos);
qsizetype itemAt(const QPoint &pos);
void moveItemTo(const QPoint &pos);
QPoint initialItemPosition(const QPainterPath &path);
QPoint randomItemPosition();
@ -53,7 +54,7 @@ private:
const PointerToMemberFunction &member);
//! [2]
QList<ShapeItem> shapeItems;
QList<ShapeItem *> shapeItems;
QPainterPath circlePath;
QPainterPath squarePath;
QPainterPath trianglePath;