如何根据第一个选定项在图形场景中对齐图形项?

时间:2018-07-30 11:57:41

标签: qt qt5 qgraphicsscene

我有图形场景,我必须根据第一个选择的项目(参考项目)上下左右。我搜索了一些代码,但在此过程中它与场景正确的位置对齐。我必须根据第一个选定的项目对齐项目。我怎样才能做到这一点?

    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);
      }

    }

更多详情

输出应类似于此输出

2 个答案:

答案 0 :(得分:1)

替换topLeft.x-对于将topLeft.x右对齐,对于顶部对齐将dy替换topLeft.y和dx,对于将底部对齐将dy替换bottomLeft.y和dx

    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);
       }
    }

答案 1 :(得分:0)

解决方法是将确定右,左,上,下的点映射到第一项的场景,而其他项则获得必须补偿的差异。

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());
    }
}

在此示例中,您可以使用向上,向下,向左,向右键移动项目。

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();
}

完整的示例可以在下面的link中找到。