I am trying to do snapping on grid such that whatever I will draw it should take only gridpoints and no other points. I have made grid in cadgraphicsscene.cpp and made different class for snapping. My grid is made as follows:
cadgraphicscene.cpp
void CadGraphicsScene::drawBackground(QPainter *painter, const QRectF &rect)
{
const int gridSize = 50;
const int realLeft = static_cast<int>(std::floor(rect.left()));
const int realRight = static_cast<int>(std::ceil(rect.right()));
const int realTop = static_cast<int>(std::floor(rect.top()));
const int realBottom = static_cast<int>(std::ceil(rect.bottom()));
// Draw grid.
const int firstLeftGridLine = realLeft - (realLeft % gridSize);
const int firstTopGridLine = realTop - (realTop % gridSize);
QVarLengthArray<QLine, 100> lines;
for (qreal x = firstLeftGridLine; x <= realRight; x += gridSize)
lines.append(QLine(x, realTop, x, realBottom));
for (qreal y = firstTopGridLine; y <= realBottom; y += gridSize)
lines.append(QLine(realLeft, y, realRight, y));
painter->setPen(QPen(QColor(220, 220, 220), 0.0));
painter->drawLines(lines.data(), lines.size());
// Draw axes.
painter->setPen(QPen(Qt::lightGray, 0.0));
painter->drawLine(0, realTop, 0, realBottom);
painter->drawLine(realLeft, 0, realRight, 0);
}
My snap class looks as follows:
snap.cpp
#include "snap.h"
#include <QApplication>
Snap::Snap(const QRect& rect, QGraphicsItem* parent,
QGraphicsScene* scene):
QGraphicsRectItem(QRectF())
{
setFlags(QGraphicsItem::ItemIsSelectable |
QGraphicsItem::ItemIsMovable |
QGraphicsItem::ItemSendsGeometryChanges);
}
void Snap::mousePressEvent(QGraphicsSceneMouseEvent *event){
offset = pos() - computeTopLeftGridPoint(pos());
QGraphicsRectItem::mousePressEvent(event);
}
QVariant Snap::itemChange(GraphicsItemChange change,
const QVariant &value)
{
if (change == ItemPositionChange && scene()) {
QPointF newPos = value.toPointF();
if(QApplication::mouseButtons() == Qt::LeftButton &&
qobject_cast<CadGraphicsScene*> (scene())){
QPointF closestPoint = computeTopLeftGridPoint(newPos);
return closestPoint+=offset;
}
else
return newPos;
}
else
return QGraphicsItem::itemChange(change, value);
}
QPointF Snap::computeTopLeftGridPoint(const QPointF& pointP){
CadGraphicsScene* customScene = qobject_cast<CadGraphicsScene*> (scene());
int gridSize = customScene->getGridSize();
qreal xV = floor(pointP.x()/gridSize)*gridSize;
qreal yV = floor(pointP.y()/gridSize)*gridSize;
return QPointF(xV, yV);
}
snap.h
#ifndef SNAP_H
#define SNAP_H
#include <QGraphicsRectItem>
#include "cadgraphicsscene.h"
class Snap : public QGraphicsRectItem
{
public:
Snap(const QRect& rect, QGraphicsItem* parent,
QGraphicsScene* scene);
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);
QVariant itemChange(GraphicsItemChange change,
const QVariant &value);
private:
QPointF offset;
QPointF computeTopLeftGridPoint(const QPointF &pointP);
};
#endif // SNAP_H
But nothing happened, no snapping is done. Can you please help me in the above?
One of the problems is that you pass QRect()
to the QGraphicsRectItem
constructor in the initialization list of Snap
class. This means it will have 0 width and height. Instead pass the same QRect
object that you pass to your snap constructor:
Snap::Snap(const QRect& rect, QGraphicsItem* parent, QGraphicsScene* scene) :
QGraphicsRectItem(rect)
You also don't seem to use the parent and the scene arguments so you might as well leave them out:
Snap::Snap(const QRect& rect) :
QGraphicsRectItem(rect)
Or if you plan to use the parent for something then you can set a default value to 0 in the declaration:
Snap(const QRect& rect, QGraphicsItem* parent = 0);
Then pass them both to the base class constructor:
Snap::Snap(const QRect& rect, QGraphicsItem* parent) :
QGraphicsRectItem(rect, parent)
snap.h
#ifndef SNAP_H
#define SNAP_H
#include <QGraphicsRectItem>
class Snap : public QGraphicsRectItem
{
public:
Snap(const QRect &rect, QGraphicsItem *parent = 0);
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);
QVariant itemChange(GraphicsItemChange change,
const QVariant &value);
private:
QPointF offset;
QPointF computeTopLeftGridPoint(const QPointF &pointP);
};
#endif // SNAP_H
snap.cpp
#include "snap.h"
#include <QDebug>
#include <qmath.h>
Snap::Snap(const QRect& rect, QGraphicsItem* parent) :
QGraphicsRectItem(rect, parent)
{
setFlags(QGraphicsItem::ItemIsSelectable |
QGraphicsItem::ItemIsMovable |
QGraphicsItem::ItemSendsGeometryChanges);
}
void Snap::mousePressEvent(QGraphicsSceneMouseEvent *event){
offset = pos() - computeTopLeftGridPoint(pos());
QGraphicsRectItem::mousePressEvent(event);
}
QVariant Snap::itemChange(GraphicsItemChange change,
const QVariant &value)
{
qDebug()<<"inside itemChange";
if (change == ItemPositionChange && scene())
{
QPointF newPos = value.toPointF();
QPointF closestPoint = computeTopLeftGridPoint(newPos);
return closestPoint+=offset;
}
else
return QGraphicsItem::itemChange(change, value);
}
QPointF Snap::computeTopLeftGridPoint(const QPointF& pointP){
int gridSize = 100;
qreal xV = qFloor(pointP.x()/gridSize)*gridSize;
qreal yV = qFloor(pointP.y()/gridSize)*gridSize;
return QPointF(xV, yV);
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QGraphicsView>
#include <QLayout>
#include "snap.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
centralWidget()->setLayout(new QVBoxLayout);
QGraphicsView *view = new QGraphicsView(this);
centralWidget()->layout()->addWidget(view);
Snap *snap = new Snap(QRect(0,0,100,100));
view->setScene(new QGraphicsScene);
view->scene()->addItem(snap);
}
MainWindow::~MainWindow()
{
delete ui;
}