PDA

View Full Version : mouseEvent in QScrollArea giving wrong position ?



barnabyr
15th April 2006, 03:29
Hi !

I Have a subclassed QScrollArea with a grid layout and it is dynamically filled with lots of thumbnails.
Each thumbnail image is placed into a QFrame which is then added into the grid layout
.. When they are all added I call adjustSize() and show the scrollarea.

I have reimplemented the scroll area's mousePressEvent(QMouseEvent *e) and to query
whether a thumbnail is being clicked my code is like this:



for (int i = 0; i < m_grdLayout->count(); i++)
{
QLayoutItem *layoutItem = m_grdLayout->itemAt(i);
if (layoutItem->geometry().contains(e->pos()))
{
return layoutItem->widget();
}
}


It didn't work and I investigated it ... it seemed that the y coordinate e->pos() was
returning were always the same .. regardless of the size of the scroll area or where I
clicked within it. (up the top or down the bottom)

It was like the postion was relative to the boundary of the containing widget .. not the
scroll area.

I tried using every mapTo and mapFrom I could think of to transform pos of but I could
never get the position in the mouse event to be relative to the place in the scroll area it
was supposed to be.

so I changed my code to :


for (int i = 0; i < m_grdLayout->count(); i++)
{
QLayoutItem *layoutItem = m_grdLayout->itemAt(i);
QWidget * w = layoutItem->widget();
if (w->underMouse())
return w;
}

which works properly.

But why didn't my first try work ? What was I doing wrong ?

thanks for any pointers

barnaby.

wysota
15th April 2006, 12:55
Can we see the whole code of the event handler?

barnabyr
16th April 2006, 22:05
constructor ...


// Thumbnail View Constructor ..
RoboThumbnailView::RoboThumbnailView(QWidget * parent) : QScrollArea(parent)
{
m_bDragging = false;
m_wgtViewport = new QWidget();
m_grdLayout = new QGridLayout();
m_grdLayout->setSpacing(5);
m_wgtViewport->setLayout(m_grdLayout);
setWidget(m_wgtViewport);
}


mousePressEvent :


void RoboThumbnailView::mousePressEvent(QMouseEvent *e)
{
RoboThumbnailClickable * thumb = thumbAt(e->pos());
if (thumb)
{
if (e->button() == Qt::RightButton)
{
// do context menu.
}
else if (e->button() == Qt::LeftButton || e->button() == Qt::MidButton)
{
m_bDragging = true;
if (e->modifiers() & Qt::ControlModifier)
{
thumb->toggleSelected();
}
else
{
for (int i = 0; i < m_grdLayout->count(); i++)
{
QLayoutItem * child = m_grdLayout->itemAt(i);
static_cast<RoboThumbnailClickable *>(child->widget())->setSelected(false);
}
thumb->setSelected(true);
}
}
}
}

thumbAt function that doesn't work ...


RoboThumbnailClickable * RoboThumbnailView::thumbAt(const QPoint & pos)
{
for (int i = 0; i < m_grdLayout->count(); i++)
{
QLayoutItem *layoutItem = m_grdLayout->itemAt(i);
if (layoutItem->geometry().contains(pos()))
{
return static_cast<RoboThumbnailClickable *>(layoutItem->widget());
}
}

return NULL;

}

thanks

wysota
19th April 2006, 19:24
if (e->button() == Qt::RightButton)
{
// do context menu.
}

There is a specialised event generated for context menus (contextMenuEvent). It's better to handle it that way.

About your problem now...

Try this:

RoboThumbnailClickable * thumb = thumbAt(e->pos()+QPoint(horizontalScrollBar()->value(), verticalScrollBar()->value()));

instead of
RoboThumbnailClickable * thumb = thumbAt(e->pos());

and see if it changes anything.

jpn
19th April 2006, 19:53
You can get the "actual" position by mapping the event's position (which is relative to the scroll area) from the widget's (inside the scroll area) point of view.



QPoint pos = widget()->mapFromParent(e->pos());
RoboThumbnailClickable * thumb = thumbAt(pos);

barnabyr
19th April 2006, 21:39
They both work .. :)

Although the mapFromParent solution makes no sense to me ... :confused:

"From parent" would imply that .. the position in e->pos() is in parent
coordinates which was what I was finding to be true. ( ie. the y coordinate was
relative to the parent window not the scroll area) BUT .. the event handler
is part of my QScrollArea .. not my parent window, so why wasn't
e->pos() passed as the correct position in the first place ?

And Wysota thanks for the reminder about contextMenuEvent . I guess I assumed
it wouldn't be available ...

wysota
19th April 2006, 22:13
Although the mapFromParent solution makes no sense to me ... :confused:

"From parent" would imply that .. the position in e->pos() is in parent
coordinates which was what I was finding to be true. ( ie. the y coordinate was
relative to the parent window not the scroll area) BUT .. the event handler
is part of my QScrollArea .. not my parent window, so why wasn't
e->pos() passed as the correct position in the first place ?
"the parent" is probably the QScrollArea widget (the widget which handles the event), and you want its viewport, thus you have to map from the scroll area widget to its "canvas" coordinates. That's exactly the same what my solution does (seems that Trolls use the scrollbar version in their examples, at least the one I've seen -- namely the pie view example).


And Wysota thanks for the reminder about contextMenuEvent . I guess I assumed it wouldn't be available ...

Just remember that context menus can be handled in three different ways in Qt4. Choose the one which suits you best.

xtfllbl
17th July 2009, 09:40
Please use mapToXXX or mapFromXXX to solve the problem.