How can I recognize QGraphicsView mouse move event? - c++

I am new in qt and c++. I have a qgraphicsview to plot signal. I would zoom specific area with mouse clicking and rectangle drawing. So I need mouse pressed position and dragged position. For this I do such this:
in header file:
#include <QtWidgets/QMainWindow>
#include <QGraphicsScene>
#include <QMouseEvent>
#include <QGraphicsSceneMouseEvent>
#include "ui_QtGuiApplication.h"
class QtGuiApplication : public QMainWindow
{
Q_OBJECT
public:
QtGuiApplication(QWidget *parent = Q_NULLPTR);
protected:
void mouseMoveEvent(QMouseEvent* event);
void mousePressEvent(QMouseEvent* event);
bool eventFilter(QObject *obj, QEvent *ev);
private:
Ui::QtGuiApplicationClass ui;
QPoint Zoom_point1_;
QPoint Zoom_point2_;
QGraphicsScene* scene = new QGraphicsScene();
};
in source file:
QtGuiApplication::QtGuiApplication(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
ui.graphicsView->installEventFilter(this);
ui.graphicsView->setMouseTracking(true);
}
bool QtGuiApplication::eventFilter(QObject * obj, QEvent * ev)
{
if (obj == ui.graphicsView)
if (ev->type() == QEvent::MouseMove)
{
QMouseEvent *mEvent = (QMouseEvent*)ev;
Zoom_point2_ = mEvent->pos();
}
return false;
}
void QtGuiApplication::mouseMoveEvent(QMouseEvent * ev)
{
Zoom_point2_ = ev->globalPos();
//do some thing …
}
void QtGuiApplication::mousePressEvent(QMouseEvent * ev)
{
Zoom_point1_ = ev->globalPos();
}
When I press and move mouse in graphicsview, I can recognize the clicked position but mouseMoveEvent(QMouseEvent * ev) never be calle. and also obj == ui.graphicsView statement in eventFilter never be occurred.What's wrong with me? How can I fix it?

By Installing event filter on the viewport of the QgraphicsView object such as
ui.graphicsView->viewport()->installEventFilter(this);
and adding below condition on eventfilter
if (ui.graphicsView->viewport())
if (ev->type() == QEvent::MouseMove)
{
QMouseEvent *mEvent = (QMouseEvent*)ev;
Zoom_point2_ = mEvent->pos();
}
problem solved.

Related

Implemented a QKeyEvent but how does the keyPressEvent() gets called

keypress.h
#ifndef KEYPRESS_H
#define KEYPRESS_H
#include <QObject>
#include <QKeyEvent>
class keypress : public QObject {
Q_OBJECT public:
explicit keypress(QObject *parent = nullptr);
void keyPressEvent(QKeyEvent *e);
};
#endif // KEYPRESS_H
keypress.cpp
#include "keypress.h"
#include <QDebug>
keypress::keypress(QObject *parent)
: QObject{parent}
{
}
void keypress::keyPressEvent(QKeyEvent *e)
{
qDebug() <<"Key clicked : "<<e->key();
}
I am new to QKeyEvent and I am not able to call the keyPressEvent function. Should i call the keyPressEvent function inside the constructor?
I also have to display a connect with keyPressEvent function and a timer of 50 milli seconds even if it doesn't receive any keypress.
Thanks in Advance!
If you want to implement keyPressEvent in the widget/dialog/control, you can override keyPressEvent.
Here is another link:
QWidget keyPressEvent override
if you want to implement key press yourself and installed on other widgets, you can refer to the code below,
From QObject::installEventFilter,
class KeyPressEater : public QObject
{
Q_OBJECT
...
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
};
bool KeyPressEater::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
qDebug("Ate key press %d", keyEvent->key());
return true;
} else {
// standard event processing
return QObject::eventFilter(obj, event);
}
}
And here's how to install it on two widgets:
KeyPressEater *keyPressEater = new KeyPressEater(this);
QPushButton *pushButton = new QPushButton(this);
QListView *listView = new QListView(this);
pushButton->installEventFilter(keyPressEater);
listView->installEventFilter(keyPressEater);
Hope it helps you.

How to get global geometry of child widget

I have label inside custom frame.
I try to movement of MainWindow (all aplication) on mouse event:
void settingslogolabel::mouseMoveEvent(QMouseEvent *ev)
{
if ((ev->buttons() & Qt::LeftButton) && firstCIsNotNull){
window()->move( mapToGlobal(ev->pos() - m_dragPosition - this->geometry().topLeft()));
}
}
BUT! this->geometry() returns local geometry.
So, how can I get global geometry of child?
What I try to make:
When you press mouse and move - all application should move as your cursor move, until you up mouse button. I want to make this interactive for label.
Full code:
HPP:
#ifndef SETTINGSLOGOLABEL_H
#define SETTINGSLOGOLABEL_H
#include <QLabel>
#include <QWidget>
#include <QMouseEvent>
class settingslogolabel : public QLabel
{
Q_OBJECT
public:
explicit settingslogolabel(QWidget *parent = 0);
void mouseMoveEvent(QMouseEvent *ev);
void mousePressEvent(QMouseEvent *ev);
void mouseReleaseEvent(QMouseEvent *ev);
private:
QPoint m_dragPosition;
bool firstCIsNotNull = true;
private:
};
#endif // SETTINGSLOGOLABEL_H
CPP:
#include "settingslogolabel.hpp"
settingslogolabel::settingslogolabel(QWidget *parent) :
QLabel(parent)
{
}
void settingslogolabel::mouseMoveEvent(QMouseEvent *ev)
{
if ((ev->buttons() & Qt::LeftButton) && firstCIsNotNull){
window()->move( mapToGlobal(ev->pos() - m_dragPosition - this->geometry().topLeft()));
}
}
void settingslogolabel::mousePressEvent(QMouseEvent *ev)
{
if (ev->button() == Qt::LeftButton) {
m_dragPosition = ev->pos();
firstCIsNotNull = true;
}
}
void settingslogolabel::mouseReleaseEvent(QMouseEvent *ev)
{
if (ev->button() == Qt::LeftButton) {
firstCIsNotNull = false;
}
}
Not sure I fully understand the problem but, the global coordinates of the top left corner of a widget can be found -- from within that widget's member functions -- using...
mapToGlobal(QPoint(0, 0));
Similarly, the global geometry would be...
rect().translated(mapToGlobal(QPoint(0, 0)));
Edit:
If the aim is to allow dragging of the top level window then your mouseMoveEvent implementation should be something like (untested)...
void settingslogolabel::mouseMoveEvent (QMouseEvent *ev)
{
if ((ev->buttons() & Qt::LeftButton) && firstCIsNotNull) {
auto delta = ev->pos() - m_dragPosition;
window()->move(window()->pos() + delta);
}
}

How to mix mouseEnterEvent and mouseMove?

in my application I try to connect nodes with lines. I use a QGraphicsView with a QGraphicsScene and my own QGraphicsItems. Now if I click on an item I want to draw a line to another node. To give a visual feedback, the goal should change color if the mouse hovers over the goal. The basics works so far, but my problem is that if I drag a line with the mouse (via mouseMoveEvent), I do not get any hoverEvents any more. I replicated the behaviour with this code:
Header File:
#pragma once
#include <QtWidgets/Qwidget>
#include <QGraphicsItem>
#include <QGraphicsScene>
class HaggiLearnsQt : public QWidget
{
Q_OBJECT
public:
HaggiLearnsQt(QWidget *parent = Q_NULLPTR);
};
class MyScene : public QGraphicsScene
{
public:
MyScene(QObject* parent = 0);
void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent);
};
class MyItem : public QGraphicsItem
{
public:
MyItem(QGraphicsItem* parent = Q_NULLPTR);
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
bool mouseOverItem;
};
Implementation:
#include "HaggiLearnsQt.h"
#include <QMessageBox>
#include <QFrame>
#include <QHBoxLayout>
#include <QGraphicsView>
MyScene::MyScene(QObject* parent)
{}
void MyScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
QGraphicsScene::mouseMoveEvent(mouseEvent);
}
MyItem::MyItem(QGraphicsItem* parent) : mouseOverItem(false)
{
setAcceptHoverEvents(true);
}
QRectF MyItem::boundingRect() const
{
return QRectF(-50, -50, 50, 50);
}
void MyItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
QBrush b = QBrush(Qt::black);
if(mouseOverItem)
b = QBrush(Qt::yellow);
painter->setBrush(b);
painter->drawRect(boundingRect());
}
void MyItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
mouseOverItem = true;
QGraphicsItem::hoverEnterEvent(event);
}
void MyItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
mouseOverItem = false;
QGraphicsItem::hoverLeaveEvent(event);
}
HaggiLearnsQt::HaggiLearnsQt(QWidget *parent)
: QWidget(parent)
{
QHBoxLayout* layout = new QHBoxLayout(this);
MyScene* graphicsScene = new MyScene();
QGraphicsView* graphicsView = new QGraphicsView();
graphicsView->setRenderHint(QPainter::RenderHint::Antialiasing, true);
graphicsView->setScene(graphicsScene);
layout->addWidget(graphicsView);
graphicsView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
graphicsView->setMinimumHeight(200);
graphicsView->setMinimumWidth(200);
graphicsView->setStyleSheet("background-color : gray");
MyItem* myitem = new MyItem();
myitem->setPos(50, 50);
graphicsScene->addItem(myitem);
}
And the default main.cpp:
#include "HaggiLearnsQt.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
HaggiLearnsQt w;
w.show();
return a.exec();
}
If you run the code, a box appears in the middle of the window. If you hover over the box, it changes color. Now try to klick outside the box and drag wiht pressed button into the box. The box does not receive a hover and does not change color.
So my question is: Can I somehow change the item while I move the mouse with a pressed button?
You can get the hovered item passing mouseEvent->scenePos() to the QGraphicsScene::itemAt method inside the scene mouse move event handler.
Have a pointer to a MyItem instance, in MyScene:
class MyScene : public QGraphicsScene
{
MyItem * hovered;
//...
initialize it to zero in MyScene constructor:
MyScene::MyScene(QObject* parent)
{
hovered = 0;
}
then use it to track the current highlighted item (if there's one):
void MyScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
if(mouseEvent->buttons())
{
QGraphicsItem * item = itemAt(mouseEvent->scenePos(), QTransform());
MyItem * my = dynamic_cast<MyItem*>(item);
if(my != 0)
{
qDebug() << mouseEvent->scenePos();
if(!my->mouseOverItem)
{
my->mouseOverItem = true;
my->update();
hovered = my;
}
}
else
{
if(hovered != 0)
{
hovered->mouseOverItem = false;
hovered->update();
hovered = 0;
}
}
}
QGraphicsScene::mouseMoveEvent(mouseEvent);
}
The line if(mouseEvent->buttons()) at the beginning prevents the check to be performed if no mouse button is held.
Don't forget to initialize mouseOverItem to false in MyItem constructor:
MyItem::MyItem(QGraphicsItem* parent) : mouseOverItem(false)
{
setAcceptHoverEvents(true);
mouseOverItem = false;
}

How to remove cropped rect from QImage/QLabel?

I did sub-classing to include mouse click function. Here, a rectangle can be chosen by mousePressEvent, mouseMoveEvent and mouseReleaseEvent. When I am trying to chose another rectangle, my previous rectangle is not being removed. It is still displaying with my previous drawn rectangle, which I don't want to display. I want to chose and display only one rectangle. I meant when I press again to chose another rectange, the previous one should be removed.
I included here my subclass named mouse_crop
mouse_crop.h is as follows
#ifndef MOUSE_CROP_H
#define MOUSE_CROP_H
#include <QMainWindow>
#include <QObject>
#include <QWidget>
#include <QMouseEvent>
#include <QLabel>
#include <QRubberBand>
class mouse_crop : public QLabel
{
Q_OBJECT
public:
mouse_crop(QWidget *parent=0);
QRubberBand *rubberBand;
QPoint origin, ending;
protected:
void mousePressEvent(QMouseEvent *ev);
void mouseMoveEvent(QMouseEvent *ev);
void mouseReleaseEvent(QMouseEvent *ev);
signals:
void sendMousePosition(QPoint&);
void sendMouseEnding(QPoint&);
};
#endif // MOUSE_CROP_H`
And mouse_crop.cpp is as follows
#include "mouse_crop.h"
mouse_crop::mouse_crop(QWidget *parent):QLabel (parent)
{
}
void mouse_crop::mousePressEvent(QMouseEvent *ev)
{
origin = ev->pos();
rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
if(ev->button()== Qt::LeftButton || ev->button()== Qt::RightButton)
{
rubberBand->show();
emit sendMousePosition(origin);
}
}
void mouse_crop::mouseMoveEvent(QMouseEvent *ev)
{
rubberBand->setGeometry(QRect(origin, ev->pos()).normalized());
}
void mouse_crop::mouseReleaseEvent(QMouseEvent *ev)
{
ending = ev->globalPos();
if(ev->button()== Qt::LeftButton || ev->button()== Qt::RightButton)
{
emit sendMouseEnding(ending);
}
}
Can any one tell me how to solve this? Thanks in advance.
The problem is caused because every time you press the mouse you are creating a new QRubberBand, what you must do is create only a QRubberBand, hide it and show it when necessary.
mouse_crop::mouse_crop(QWidget *parent)
: QLabel(parent)
{
rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
rubberBand->hide();
}
void mouse_crop::mousePressEvent(QMouseEvent *ev)
{
origin = ev->pos();
rubberBand->setGeometry(QRect(origin, origin));
if(ev->button()== Qt::LeftButton || ev->button()== Qt::RightButton)
{
rubberBand->show();
emit sendMousePosition(origin);
}
}
void mouse_crop::mouseMoveEvent(QMouseEvent *ev)
{
rubberBand->setGeometry(QRect(origin, ev->pos()).normalized());
}
void mouse_crop::mouseReleaseEvent(QMouseEvent *ev)
{
ending = ev->globalPos();
if(ev->button()== Qt::LeftButton || ev->button()== Qt::RightButton)
{
emit sendMouseEnding(ending);
}
}

QWidget does not respond after a mouse press event.

I am trying to get a mouse press event to work with my widget I created but every time I click the widget, the window stops responding and I have to kill the program. Does anyone know how to fix this and also how to get the color to change?
Here is the .h and the .cpp files.
.cpp file:
#include "iconwidget.h"
#include <QPaintEvent>
#include <QPainter>
#include <QPainterPath>
iconWidget::iconWidget(QWidget *parent) :
QWidget(parent)
{
this->resize(ICON_WIDGET_WIDTH,ICON_WIDGET_HEIGHT);
pressed = false;
}
void iconWidget::paintEvent(QPaintEvent *event)
{
QRect areatopaint = event->rect();
QPainter painter(this);
QBrush brush(Qt::black);
QPointF center = this->rect().center();
QPainterPath icon;
icon.addEllipse(center,20,20);
painter.drawPath(icon);
painter.fillPath(icon, brush);
if (pressed) {
brush.setColor(Qt::red);
}
}
void iconWidget::mousePressEvent(QMouseEvent *event)
{
pressed = true;
update();
iconWidget::mousePressEvent(event);
}
.h file:
#define ICONWIDGET_H
#include <QWidget>
#define ICON_WIDGET_WIDTH 45
#define ICON_WIDGET_HEIGHT 45
class iconWidget : public QWidget
{
Q_OBJECT
public:
explicit iconWidget(QWidget *parent = 0);
void paintEvent(QPaintEvent *event);
bool pressed;
protected:
void mousePressEvent(QMouseEvent *event);
};
#endif // ICONWIDGET_H
You call mousePressEvent() in an endless recursion. You should change the line:
iconWidget::mousePressEvent(event);
in your mousePressEvent function to:
QWidget::mousePressEvent(event);