I have Graphic scene in that i have to alight right,left,top or bottom based on first selected item(Reference Item). i searched i got some code but in this its aligning to scene right position. I have to align items based on first selected item. how can i do this?
void GraphicScene::ItemsRightAlign()
{
if (selectedItems().isEmpty())
return;
QRectF refRect = selectedItems().first()->boundingRect();
QList<QGraphicsItem*> sel =selectedItems(); // for example
foreach(QGraphicsItem* selItem, sel)
{
qreal dx = 0, dy = 0;
QRectF itemRect = selItem->mapToScene(selItem->boundingRect()).boundingRect();
//if(align_right)
dx = refRect.right() - itemRect.right();
qDebug() << "item pos "<< dx << dy << selItem->mapToScene(selItem->boundingRect()).boundingRect() ;
selItem->moveBy(dx, dy);
}
}
For more details
Output should be like this output
The resolution method is to map the point that determines the right, left, up, down to the scene of the first item and the other items obtaining the difference that must be compensated.
graphicsscene.h
#ifndef GRAPHICSSCENE_H
#define GRAPHICSSCENE_H
#include <QGraphicsScene>
#include <QGraphicsItem>
class GraphicsScene: public QGraphicsScene{
Q_OBJECT
public:
GraphicsScene(QObject *parent=nullptr);
void moveSelecteds(Qt::Alignment aligment);
private slots:
void onSelectionChanged();
private:
void move(QGraphicsItem *ref, QList<QGraphicsItem *> others, Qt::Alignment aligment);
QGraphicsItem *mRef;
};
#endif // GRAPHICSSCENE_H
graphicsscene.cpp
#include "graphicsscene.h"
GraphicsScene::GraphicsScene(QObject *parent):
QGraphicsScene(parent),
mRef(nullptr)
{
connect(this, &GraphicsScene::selectionChanged, this, &GraphicsScene::onSelectionChanged);
}
void GraphicsScene::moveSelecteds(Qt::Alignment aligment){
QList<QGraphicsItem *> its= selectedItems();
if(its.size() < 2)
return;
if(!its.removeOne(mRef))
return;
move(mRef, its, aligment);
}
void GraphicsScene::onSelectionChanged(){
if(selectedItems().isEmpty()){
mRef = nullptr;
}
else if(selectedItems().size() == 1){
mRef = selectedItems().first();
}
}
void GraphicsScene::move(QGraphicsItem *ref, QList<QGraphicsItem *> others, Qt::Alignment aligment){
QPointF p;
switch (aligment) {
case Qt::AlignLeft:
p = QPointF(ref->mapToScene(ref->boundingRect().topLeft()).x(), 0);
break;
case Qt::AlignRight:
p = QPointF(ref->mapToScene(ref->boundingRect().topRight()).x(), 0);
break;
case Qt::AlignTop:
p = QPointF(0, ref->mapToScene(ref->boundingRect().topLeft()).y());
break;
case Qt::AlignBottom:
p = QPointF(0, ref->mapToScene(ref->boundingRect().bottomLeft()).y());
break;
}
for(QGraphicsItem *o: others){
QPointF delta;
switch (aligment) {
case Qt::AlignLeft:{
delta = p - QPointF(o->mapToScene(o->boundingRect().topLeft()).x(), 0);
break;
}
case Qt::AlignRight:{
delta = p - QPointF(o->mapToScene(o->boundingRect().topRight()).x(), 0);
break;
}
case Qt::AlignTop:{
delta = p - QPointF(0, o->mapToScene(o->boundingRect().topLeft()).y());
break;
}
case Qt::AlignBottom:{
delta = p - QPointF(0, o->mapToScene(o->boundingRect().bottomLeft()).y());
break;
}
}
o->moveBy(delta.x(), delta.y());
}
}
In this example you can use the up, down, left, right keys to move the items.
main.cpp
#include "graphicsscene.h"
#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QShortcut>
#include <random>
static void create_items(QGraphicsScene & scene){
std::default_random_engine generator;
std::uniform_int_distribution<int> dist_size(30, 40);
std::uniform_int_distribution<int> dist_pos(-50, 50);
for(const QString & colorname : {"red", "green", "blue", "gray", "orange"}){
QRectF r(QPointF(dist_pos(generator), dist_pos(generator)),
QSizeF(dist_size(generator), dist_size(generator)));
auto item = new QGraphicsRectItem(r);
item->setPos(QPointF(dist_pos(generator), dist_pos(generator)));
item->setBrush(QColor(colorname));
item->setFlag(QGraphicsItem::ItemIsSelectable);
scene.addItem(item);
}
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
GraphicsScene scene;
create_items(scene);
QGraphicsView view(&scene);
const QList<QPair<Qt::Key, Qt::Alignment>> k_a {
{Qt::Key_Up, Qt::AlignTop},
{Qt::Key_Down, Qt::AlignBottom},
{Qt::Key_Left, Qt::AlignLeft},
{Qt::Key_Right, Qt::AlignRight}
};
for(const QPair<Qt::Key, Qt::Alignment> & p : k_a){
QShortcut *shorcut = new QShortcut(p.first, &view);
QObject::connect(shorcut, &QShortcut::activated, std::bind(&GraphicsScene::moveSelecteds, &scene, p.second));
}
view.resize(640, 480);
view.show();
return a.exec();
}
The complete example can be found in the following link.
Replace topLeft.x -- for Right align with topRight.x ,For Top Align replace topLeft.y and dx with dy,For Bottom Align replace bottomLeft.y and dx with dy
void GraphicScene::ItemsLeftAlign
{
if (selectedItems().isEmpty())
return;
QGraphicsItem *FirstSelItem = selectedItems().first();
QList<QGraphicsItem*> sel =selectedItems(); // for example
foreach(QGraphicsItem* selItem, sel)
{
qreal dx = 0, dy = 0;
dx = (FirstSelItem->mapToScene(FirstSelItem->boundingRect().topLeft()).x()) -
(selItem->mapToScene(selItem->boundingRect().topLeft()).x());
selItem->moveBy(dx, dy);
}
}