PDA

View Full Version : resize Rectangle using mouse events



coder2020
26th July 2020, 15:49
Hi

I'm trying to resize a rectangle and move it with the mouse.

at the moment i managed to move it with the mouse but i have a little problem resizing it.

When I resize it from the top of the rectangle, I have no problem but when I resize it from the bottom, I manage to do it as long as I don't release the mouse button but once release it, I can't resize it anymore until I move the rectangle.

In addition, there are traces in the window when I decrease the height of the bottom rectangle.

can you help me find where the bug is coming from?


main.cpp


#include "fenetre.h"
#include <QApplication>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Fenetre w;
w.show();

return a.exec();
}


fenetre.h



#ifndef FENETRE_H
#define FENETRE_H

#include <QGraphicsScene>
#include <QMainWindow>

#include "myrectangle.h"
#include <QGraphicsView>

#include <QMouseEvent>
#include <QObject>

namespace Ui {
class Fenetre;
}

class Fenetre : public QMainWindow
{
Q_OBJECT

public:
explicit Fenetre(QWidget *parent = nullptr);
~Fenetre();

bool eventFilter(QObject *obj, QEvent *event);

protected:


private:
Ui::Fenetre *ui;

QGraphicsScene *scene;
QGraphicsView *view;

MyRectangle *rectangle;

signals:
void clickedMouse(int x, int y);
};

#endif // FENETRE_H


fenetre.cpp



#include "fenetre.h"
#include "ui_fenetre.h"

Fenetre::Fenetre(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Fenetre)
{
ui->setupUi(this);

QBrush greenBrush(Qt::green);
QBrush blueBrush(Qt::blue);
QPen pen(Qt::black);
pen.setWidth(2);

rectangle = new MyRectangle ();

QColor c (242,251,235);
QBrush brush (c, Qt::SolidPattern);

scene = new QGraphicsScene(this);
scene->setBackgroundBrush(brush);
scene->addItem(rectangle);

view = new QGraphicsView(scene);
scene->setSceneRect(0, 0, 400, 400);
ui->graphicsView->setScene(scene);
view->viewport()->installEventFilter(this);

setCentralWidget(view);
view->show();

connect(this, SIGNAL(clickedMouse(int, int)), rectangle, SLOT(recevedClickedMouse(int, int)));
}

Fenetre::~Fenetre()
{
delete ui;
}

bool Fenetre::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::MouseMove)
{
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
statusBar()->showMessage(QString("Mouse move (%1,%2)").arg(mouseEvent->pos().x()).arg(mouseEvent->pos().y()));

// emit clickedMouse(mouseEvent->pos().x(), mouseEvent->pos().y());
}
else if (event->type() == QEvent::MouseButtonPress)
{
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
statusBar()->showMessage(QString("Mouse move (%1,%2)").arg(mouseEvent->pos().x()).arg(mouseEvent->pos().y()));

QPoint pointRec2 = view->mapFromScene(rectangle->pos().x(), rectangle->pos().y());
qDebug() << "OKKKKKK 2222 BBBBBB view->mapFromScene(myRect.x() = " << pointRec2.x() << "myRect.y() " << pointRec2.y(); //okkk IMPORTANT

///////////////////////////
emit clickedMouse(mouseEvent->pos().x(), mouseEvent->pos().y());
}

return false;
}


myrectangle.h



#ifndef MYRECTANGLE_H
#define MYRECTANGLE_H

#include <QPainter>
#include <QGraphicsItem>
#include <QDebug>

#include <QApplication>
#include <QColor>
#include <QPen>

#include <QGraphicsSceneHoverEvent>
#include <QObject>

class MyRectangle : public QObject, public QGraphicsItem
{
Q_OBJECT

public:
MyRectangle();
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);

QColor color; // the hover event handlers will toggle this between red and black
QPen pen; // the pen is used to paint the red/black border

private:
qreal width;
qreal height;

int mouseDownX;
int mouseDownY;

bool pressedToSize;
int avant = 0;

protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);

void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);

protected slots:
void recevedClickedMouse(int x, int y);
};
#endif // MYRECTANGLE_H



myrectangle.cpp



#include "myrectangle.h"

MyRectangle::MyRectangle()
{
width = 100;
height = 50;

pressedToSize = false;
setFlag(ItemIsMovable);

setAcceptHoverEvents(true);
color = Qt::yellow;
pen.setColor(color);
}

QRectF MyRectangle::boundingRect() const
{
return QRectF(0, 0, width, height);
}

void MyRectangle::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
QRectF rec = boundingRect();
QBrush brush(Qt::blue);

if(pressedToSize)
{
brush.setColor(color);
}
else
{
brush.setColor(color);
}

painter->fillRect(rec, brush);
painter->drawRect(rec);
}


void MyRectangle::mousePressEvent(QGraphicsSceneMouseEv ent *event)
{
if(event->pos().y() < 10 || event->pos().y() > height - 10)
{
pressedToSize = true;
QApplication::setOverrideCursor(Qt::SizeVerCursor) ;
mouseDownX = event->pos().x();
mouseDownY = event->pos().y();
}
else
{
QApplication::setOverrideCursor(Qt::OpenHandCursor );
}
update();

QGraphicsItem::mousePressEvent(event);
}

void MyRectangle::mouseMoveEvent(QGraphicsSceneMouseEve nt *event)
{
if(pressedToSize)
{
if((mouseDownY <= 10)) // En haut du rectangle
{
qDebug() << "haut ";
height -= event->pos().y();
// setPos(pos().x() , pos().y() + event->pos().y() );
moveBy(0, event->pos().y());
}

else if( (avant >= height -10)) // En bas du rectangle
{
qDebug() << "bas ";
height = event->pos().y();
// setPos(pos().x() , pos().y());
// moveBy(0, 0);
}
}

avant = event->pos().y();
update();
if(!pressedToSize)
{
qDebug() << "!!!!!pressedToSize ";
QGraphicsItem::mouseMoveEvent(event);
}
}

void MyRectangle::mouseReleaseEvent(QGraphicsSceneMouse Event *event)
{
pressedToSize = false;
if((event->pos().y() >= 0 && (event->pos().y() <= 10)) || ((event->pos().y() <= height) && (event->pos().y() >= (height - 10)) ))
{
QApplication::setOverrideCursor(Qt::SizeVerCursor) ;
}
else
{
QApplication::setOverrideCursor(Qt::OpenHandCursor );
}
update();

QGraphicsItem::mouseReleaseEvent(event);
}

void MyRectangle::hoverEnterEvent(QGraphicsSceneHoverEv ent *event)
{
color = Qt::red;
if((event->pos().y() > 0 && (event->pos().y() < 10)) || ((event->pos().y() < height) && (event->pos().y() > (height - 10)) ))
{
QApplication::setOverrideCursor(Qt::SizeVerCursor) ;
}
else
{
QApplication::setOverrideCursor(Qt::OpenHandCursor );
}
update();

}

void MyRectangle::hoverMoveEvent(QGraphicsSceneHoverEve nt *event)
{
color = Qt::red;
if((event->pos().y() > 0 && (event->pos().y() < 10)) || ((event->pos().y() < height) && (event->pos().y() > (height - 10)) ))
{
QApplication::setOverrideCursor(Qt::SizeVerCursor) ;
}
else
{
QApplication::setOverrideCursor(Qt::OpenHandCursor );
}
update();
}

void MyRectangle::hoverLeaveEvent(QGraphicsSceneHoverEv ent *event)
{
color = Qt::green;
if((event->pos().y() >= 0 && (event->pos().y() <= 10)) || ((event->pos().y() <= height) && (event->pos().y() >= height - 10) ))
{
QApplication::setOverrideCursor(Qt::SizeVerCursor) ;
}
else
{
QApplication::setOverrideCursor(Qt::ArrowCursor);
}
update();
}

void MyRectangle::recevedClickedMouse(int x, int y)
{
qDebug() << "7777 x = " << x << "y = " << y << endl;
}

d_stranz
26th July 2020, 22:21
In your MyRectangle constructor, you have not called either of the base class constructors (QObject, QGraphicsItem), both of which expect a pointer to a parent object (QObject or QGraphicsItem). In any case, there -is- a QGraphicsObject class which inherits from both QObject and QGraphicsItem and you should be using that as your base class if you need signals and slots in your rectangle.

There is a logic error in your code - the mouseReleaseEvent is the only place you set pressToSize back to false. If you press the mouse inside your rectangle, and then release it -outside- the rectangle, then this release event never gets called because the rectangle no longer has the input focus. You should set it to false as the first thing in the mousePressEvent.

coder2020
28th July 2020, 18:23
Thank you very much for your answer.
If I do what you say, I get to resize the bottom of the rectangle and at the same time it moves it.
So I found the solution by adding only the function: prepareGeometryChange () at the start of the mouseMoveEvent function.
now it is working properly.