QGraphicsScene::itemAt() not working properly - c++

I am trying to find out the QGraphicsItem under the mouse (when mouse hover over the item). For that I am using itemAt() method but itemAt() is not returning QGraphicsItem.
I tried this way:
bool myViewer::eventFilter(QObject *watched, QEvent *event)
{
bool fEvent = false;
switch(event->type())
{
case QEvent::MouseButtonPress:
{....}
case QEvent::MouseButtonRelease:
{...}
case QEvent::Enter:
{
QMouseEvent * mouseEvent = static_cast<QMouseEvent *>(event);
qDebug()<<"Event points = "<< mouseEvent->pos(); // showing points properly
QPointF po = _view->mapToScene(mouseEvent->pos());
QGraphicsRectItem* rItem = qgraphicsitem_cast<QGraphicsRectItem*>(_scene->itemAt(po,QTransform()));
if(rItem)
{
// some logic
}
}
return true;
default:
break;
}
return fEvent;
I tried with QGraphicsView::itemAt() also. But still it did not work.
Note: In both way following lines works fine.
QMouseEvent * mouseEvent = static_cast<QMouseEvent *>(event);
qDebug()<<"Event points = "<< mouseEvent->pos();
Where am I wrong?

May be you can try handling QEvent::GraphicsSceneMousePress
And then get the position as said below (pseudo code. Not tetsted.)
//Get the scene event object.
QGraphicsSceneMouseEvent* sceneEvent = dynamic_cast<QGraphicsSceneMouseEvent*>(qevent);
//From the scene event object get the scene position.
QPointF po = sceneEvent->scenePos();
Use that position to find the item.

Related

How to determine mouse clicked point is inside in any QGraphicsItem from scene in Qt?

I have a QGraphicsView which contains large number of QGraphicsItem.
I want to check, mouse clicked point is inside any of QGraphicsItem or not. And if it is inside in any QGraphicsItem, that item should be highlighted.
But though the mouse clicked point is not inside in any QGraphicsItem, some of the polylines are getting highlighted.
bool myViewer::eventFilter(QObject* watched, QEvent* event)
{
bool filterEvent = false;
switch (event->type())
{
case QEvent::MouseButtonPress:
{
FindingPosition(event);
break;
}
}
}
void myViewer::FindingPosition(QEvent* event)
{
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
QPointF mousePoint = _view->mapToScene(mouseEvent->pos());
foreach(QGraphicsItem* t , _scene->items())
{
if(t->contains(t->mapFromScene(mousePoint)))
{
QGraphicsRectItem* rItem = qgraphicsitem_cast<QGraphicsRectItem*>(t);
if (rItem)
{
rItem->setSelected(false);
QPen mPen;
mPen.setWidth(1);
mPen.setBrush(Qt::red);
rItem->setPen(mPen);
break;
}
else
{
QGraphicsPathItem* pItem = qgraphicsitem_cast<QGraphicsPathItem*>(t);
if (pItem)
{
pItem->setSelected(false);
QPen mPen;
mPen.setWidth(1);
mPen.setBrush(Qt::red);
pItem->setPen(mPen);
break;
}
}
}
}
}
}

How to display some text besides mouse pointer when the mouse hover over QGraphicsItem's in Qt?

I have a QGraphicsView, which contains many rectangle and polylines. I wanted to print every object names ( every rectangle, polylines have names) once I clicked them on view through mouse click. I did that and worked perfectly.
But now I want to do that over mouse hovering. It means, if I hover a mouse over particular object, it should show its name besides cursor.
I tried that, but
I am not understanding, on hovering, how that particular object should get selected ?
And how to print its name besides cursor point ?
I tried this way:
bool myClass::eventFilter(QObject *watched, QEvent *event)
{
bool filterEvent = false;
switch(event->type())
{
case QEvent::MouseButtonPress:
{....}
case QEvent::MouseButtonRelease:
{...}
case QEvent::Enter:
{
QMouseEvent * mouseEvent = static_cast<QMouseEvent *>(event);
QPointF po = _view->mapToScene(mouseEvent->pos());
FindNamesOverHover(po);
}
return true;
default:
break;
}
return filterEvent;
}
void myClass::FindNamesOverHover(QPointF p)
{
QGraphicsRectItem* rItem = qgraphicsitem_cast<QGraphicsRectItem*>(_scene->itemAt(p,QTransform()));
if(rItem)
{
// some logic
qDebug()<< "Instance name is " << i->Name();
}
}
Constructor of class myClass
myClass::myClass(QWidget* parent) :
QDockWidget(parent)
{
scene = new QGraphicsScene(this);
view = new QGraphicsView(this);
view->setScene(_scene);
view->viewport()->installEventFilter(this);
}
Now above code works only,
When I select object through mouse click and then again hover over it.
Then it prints its name on console.
But I want only hovering ( no selection through mouse click) will show its name besides cursor point.
Can any one help me ?
You can override QGraphicsScene.mouseMoveEvent and inside it use QGraphicsScene.itemAt to query for item under cursor. To display you can use QGraphicsTextItem, just move it to correct position and apply text.

How to get mouse click and release position using override virtual paint()?

I am having QGraphicsView which contains different QGraphicsItem's like rectangle,polyline,text etc. I have installed event filter through which I am managing mouse click and release event and creating rubber band rectangle. Whichever area comes under rubber band rectangle, it gets zoom in.
I am storing rubber band rectangle points in local variables like rubberBandOrigin ( mouse click position ) and rubberBandEnd ( mouse release position)
When I click on any item's, its paint() method gets called. I want to use rubberBandOrigin and rubberBandEnd variables in paint() method.
The way I was told that, you will get these variables ( means mouse click position and release position ) through paint() itself.
paint() has 3rd parameter QWidget *widget. Through this, you will get mouse click and release position (i.e. rubber band rectangle position)
Here is my code:
bool guiSchematicViewUtil::eventFilter(QObject *watched, QEvent *event)
{
bool filterEvent = false;
switch(event->type())
{
case QEvent::MouseButtonPress:
{
QMouseEvent * mouseEvent = static_cast<QMouseEvent *>(event);
rubberBandOrigin = mouseEvent->pos();
rubberBandActive = true;
break;
}
case QEvent::MouseButtonRelease:
{
if (rubberBandActive)
{
QMouseEvent * mouseEvent = static_cast<QMouseEvent *>(event);
rubberBandEnd = mouseEvent->pos();
QGraphicsView * view = static_cast<QGraphicsView *>(watched->parent());
QRectF zoomRectInScene = QRectF(view->mapToScene(rubberBandOrigin),
view->mapToScene(rubberBandEnd));
view->fitInView(zoomRectInScene, Qt::KeepAspectRatio);
rubberBandActive = false;
}
break;
}
default:
break;
}
return filterEvent;
}
paint method:
void guiSchematicRect::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
// Here I want rubberBandOrigin and rubberBandEnd co-ordinates using QWidget* widget parameter
}
I tried with api like parent(), parentWidget() of QWidget but did not get it.
Can any one help me ?

How to constrain a QRubberBand within a QLabel?

I am building a Qt5 application that allows a user to draw a rubberband with his mouse over an image, to select certain area of the image for further processing.
I got my code to only allow the user to start drawing the rubberband, by subclassing a QLabel to a custom class (frame_displayer) which mousePressEvent() is overridden and thus be only invoked when the mouse press happens within the custom classed widget.
The problem is that when the initial click is inside the frame_displayer, mouseMoveEvent(), the function that I use to change the rubberband size accordingly, keeps getting called even when the mouse cursor has been dragged outside of the frame_displayer.
I have tried using leaveEvent() and enterEvent() to control a class boolean flag that codes inside mouseMoveEvent could rely on to know whether the cursor is still within the widget. However, both leaveEvent() and enterEvent() are only called while a mouse button is not being held, thus rendering them no use for constraining the rubberband.
Also, the underMouse() always return true, for a reason unknown to me.
Segment of frame_displayer.cpp
frame_displayer::frame_displayer(QWidget * parent) : QLabel(parent)
{
_rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
}
void frame_displayer::mousePressEvent(QMouseEvent *event)
{
_lastClickedBtn = event->button();
if (_lastClickedBtn == Qt::LeftButton)
{
_mouseOriginClickPoint = event->pos();
_rubberBand->setGeometry(QRect(_mouseOriginClickPoint, _mouseClickPoint));
_rubberBand->show();
}
}
void frame_displayer::mouseMoveEvent(QMouseEvent *event)
{
if(_rubberBand != nullptr)
{
if (this->underMouse())
{
if (_lastClickedBtn == Qt::LeftButton)
{
QPoint mouseCurrentPoint = event->pos();
_rubberBand->setGeometry(QRect(_mouseOriginClickPoint, mouseCurrentPoint).normalized());
}
}
}
}
void frame_displayer::mouseReleaseEvent(QMouseEvent *event)
{
_mouseOriginClickPoint = QPoint();
_lastClickedBtn = Qt::MidButton;
if(_rubberBand != nullptr)
{
_rubberBand->hide();
_rubberBand->clearMask();
}
}
void frame_displayer::leaveEvent(QEvent *event)
{
qDebug() << "Leaving";
}
void frame_displayer::enterEvent(QEvent *event)
{
qDebug() << "Entering";
}
Thanks in advance!
I think that's the expected behaviour. If you want to limit the extents of the rubber band then simply clamp them in the mouseMoveEvent override...
void frame_displayer::mouseMoveEvent(QMouseEvent *event)
{
if(_rubberBand != nullptr)
{
if (this->underMouse())
{
if (_lastClickedBtn == Qt::LeftButton)
{
QPoint mouseCurrentPoint = event->pos();
/*
* Clamp mouseCurrentPoint to the QRect of this widget.
*/
auto clamp_rect = rect();
mouseCurrentPoint.rx() = std::min(clamp_rect.right(), std::max(clamp_rect.left(), mouseCurrentPoint.x()));
mouseCurrentPoint.ry() = std::min(clamp_rect.bottom(), std::max(clamp_rect.top(), mouseCurrentPoint.y()));
_rubberBand->setGeometry(QRect(_mouseOriginClickPoint, mouseCurrentPoint).normalized());
}
}
}
}

A change in eventFilter function causes weird QGraphicScene behavior

I have a Qt program with a QGraphicScene inside a QGraphicsView on top of QMainWindow.
The events are handled by the QMainWindow using an eventFilter function.
The function body looks similar to this code:
bool Window::eventFilter(QObject *, QEvent *event) {
QEvent::Type type = event->type();
if (type == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
switch(keyEvent->key()) {
case Qt::Key_A:
case Qt::Key_B:
case Qt::Key_C:
case Qt::Key_D:
// call a function that uses the current mouse position on the graphics scene
break;
default:
QLocale loc = QApplication::keyboardInputLocale();
if(loc.language() != QLocale::English) {
QString message = "A non-English key was pressed";
showMessage(message, QMessageBox::Warning);
}
}
return true;
}
return false;
}
I recently added the "default" part and since then the coordinates that are used in the A,B,C,D cases are totally wrong. In addition, if I add a simple cout print anywhere in the function the bug disappears and the correct mouse coordinates are used.
What can possibly cause this?