Reputation: 71
I am trying something that would seem quite easy, but am struggling a bit with it. I want to be able to draw rectangles in a GUI. What I am doing now is:
I create a GUI with Qt Designer, in which I include a QGraphicsView.
In my main window I create a myGraphicsScene (class derived from QGraphicsScene, but with mouse press, move and release events overridden) and I set the scene to the QGraphicsView created in the UI.
The problem is that I am not able to properly control the refresh and update of the view when I change the scene.
Here is the relevant part of the code:
MainGUIWindow constructor and initialization:
MainGUIWindow::MainGUIWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainGUIWindow)
{
ui->setupUi(this);
_init();
}
void MainGUIWindow::_init()
{
scene = new myGraphicsScene(ui->frame_drawing);
scene->setSceneRect(QRectF(QPointF(-100, 100), QSizeF(200, 200)));
ui->graphicsView->setScene(scene);
QRect rect(10, 20, 80, 60);
scene->addText("Hello world!");
scene->addRect(rect, QPen(Qt::black), QBrush(Qt::blue));
}
I can perfectly see the HelloWorld text and this rectangle. However when I start with clicking events, I don't properly get updates anymore.
myGraphicsScene class header:
#ifndef MYGRAPHICSSCENE_H
#define MYGRAPHICSSCENE_H
#include <QGraphicsScene>
class QGraphicsSceneMouseEvent;
class QPointF;
class QColor;
class myGraphicsScene : public QGraphicsScene
{
Q_OBJECT
public:
explicit myGraphicsScene(QObject *parent = 0);
public slots:
signals:
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) override;
void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) override;
void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) override;
private:
QPen* pen;
QBrush* brush;
QRect* rect;
QPoint* p1;
QPoint* p2;
bool firstClick;
// bool startedRect;
};
#endif
myGraphicsScene class implementation:
#include "myGraphicsScene.h"
#include <QGraphicsSceneMouseEvent>
#include <QRect>
myGraphicsScene::myGraphicsScene(QObject *parent)
: QGraphicsScene(parent)
{
pen = new QPen(Qt::black);
brush = new QBrush(Qt::blue);
rect = 0;
// startedRect = false;
firstClick = true;
}
void myGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
if (mouseEvent->button() != Qt::LeftButton)
return;
// rect = new QRect((mouseEvent->scenePos()).toPoint(), (mouseEvent->scenePos()).toPoint());
// addRect(*rect, *pen, *brush);
// startedRect = true;
if(firstClick)
{
p1 = new QPoint((mouseEvent->scenePos()).toPoint());
QRect tmp_rect(*p1, *p1);
addRect(tmp_rect, *pen, *brush);
}
else
{
p2 = new QPoint((mouseEvent->scenePos()).toPoint());
QRect tmp_rect(*p2, *p2);
addRect(tmp_rect, *pen, *brush);
}
QGraphicsScene::mousePressEvent(mouseEvent);
}
void myGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
// if(startedRect)
// {
// rect->moveBottomRight((mouseEvent->scenePos()).toPoint());
// qDebug("Mouse Position: %d, %d", (mouseEvent->scenePos()).toPoint().x(), (mouseEvent->scenePos()).toPoint().y());
// qDebug("Rectangle BottomRight Position: %d, %d", rect->bottomRight().x(), rect->bottomRight().y());
// }
QGraphicsScene::mouseMoveEvent(mouseEvent);
}
void myGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
if (mouseEvent->button() != Qt::LeftButton)
return;
// rect = 0;
// startedRect = false;
if(firstClick)
{
firstClick = false;
}
else
{
rect = new QRect(*p1, *p2);
addRect(*rect, *pen, *brush);
p1 = 0;
p2 = 0;
rect = 0;
firstClick = true;
}
QGraphicsScene::mouseReleaseEvent(mouseEvent);
}
My original idea was to draw the rectangles in a drag and drop fashion, but in the end ended up trying the two-clicks approach, which worked a bit better but still doesn't completely update the view when it should.
I am new to Qt, so I am not very familiar with how it should be done. Any help would be appreciated, since I have been a bit stuck here for some time now.
Thanks!
Upvotes: 1
Views: 12046
Reputation: 1
one other helpful hint I found was that when I extended my view, I had put the mouse event handler under "public" instead of "protected". I made the change the calls were made consistently.
Upvotes: 0
Reputation: 71
I just found the solution: I had to actually change the item added to the scene, and not the rectangle. So, now, my code looks like:
#include "myGraphicsScene.h"
#include <QGraphicsSceneMouseEvent>
#include <QRect>
#include <QGraphicsRectItem>
myGraphicsScene::myGraphicsScene(QObject *parent)
: QGraphicsScene(parent)
{
pen = new QPen(Qt::black);
brush = new QBrush(Qt::blue);
tmp_rect = 0;
startedRect = false;
// firstClick = true;
}
void myGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
if (mouseEvent->button() != Qt::LeftButton)
return;
// Drag and drop approach
startedRect = true;
p1 = new QPointF(mouseEvent->scenePos());
tmp_rect = new QRectF(*p1, *p1);
// addRect(*tmp_rect, *pen, *brush);
tmp_rect_item = new QGraphicsRectItem(*tmp_rect);
rectangles.push_back(tmp_rect_item);
addItem(rectangles.back());
// Two-clicks approach
// if(firstClick)
// {
// p1 = new QPointF(mouseEvent->scenePos());
// tmp_rect_item = addRect(QRect(p1->toPoint(), p1->toPoint()), *pen, *brush); //save it to remove it after
// }
// else
// {
// p2 = new QPointF(mouseEvent->scenePos());
// // QRect tmp_rect(*p2, *p2);
// // addRect(tmp_rect, *pen, *brush);
// }
update();
QGraphicsScene::mousePressEvent(mouseEvent);
}
void myGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
if(startedRect)
{
tmp_rect_item->setRect(QRectF(*p1, mouseEvent->scenePos()));
qDebug("Mouse Position: %d, %d", (mouseEvent->scenePos()).toPoint().x(), (mouseEvent->scenePos()).toPoint().y());
qDebug("Rectangle BottomRight Position: %d, %d", tmp_rect->bottomRight().x(), tmp_rect->bottomRight().y());
update();
}
QGraphicsScene::mouseMoveEvent(mouseEvent);
}
void myGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
if (mouseEvent->button() != Qt::LeftButton)
return;
// Drag and drop approach:
tmp_rect = 0;
startedRect = false;
// Two-clicks approach
// if(firstClick)
// {
// firstClick = false;
// }
// else
// {
// removeItem(tmp_rect_item);
// tmp_rect_item = new QGraphicsRectItem(QRectF(*p1, *p2));
// // *tmp_rect, *pen, *brush);
// rectangles.push_back(tmp_rect_item);
// addItem(rectangles.back());
// p1 = 0;
// p2 = 0;
// tmp_rect = 0;
// firstClick = true;
// }
update();
QGraphicsScene::mouseReleaseEvent(mouseEvent);
}
Upvotes: 1
Reputation: 749
In each of your mouse*Event()
overloads, call QGraphicsScene::update()
method. It will schedule redraw on the view.
http://doc.qt.io/qt-5/qgraphicsscene.html#update
Upvotes: 4