可拖动的像素图在QGraphicsScene的图形项目中

时间:2018-03-28 14:14:33

标签: c++ qt qt5 qgraphicsitem qgraphicspixmapitem

我有一个12 * 4网格的场景和QGraphicsItems块,当我右键单击块时我有一个上下文菜单  我可以在块中添加图标 我不知道如何让这些图标可以拖动到图形场景中的其他块,我知道有"可拖动图标示例"但是如何将该代码实现为图形场景。

这是mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QGraphicsPathItem>
class QGraphicsSceneMouseEvent;
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT

public:
explicit MainWindow(QWidget *parent = 0);
bool eventFilter(QObject *, QEvent *);
~MainWindow();

private slots:
void showContextMenu(const QPoint&);
void addPixBlock();

private:
Ui::MainWindow *ui;
QGraphicsScene *scene;
QGraphicsItem *itemAt(const QPointF&);

int x;
int y;

QMenu *Menu;
QMenu *Submenu;
QAction *Picture;
QGraphicsPixmapItem* pix;
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "block.h"
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QDebug>
#include <QPainter>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
scene = new QGraphicsScene(this) ;
for(int row=-4;row<8;++row)
  for(int column=0;column<4;++column)
{
  Block *b = new Block;
  scene->addItem(b);
  b->setPos(row* 95,column*85);
}
ui->graphicsView->setScene(scene);
scene->installEventFilter(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
QGraphicsItem* MainWindow::itemAt(const QPointF &pos)
{
QList<QGraphicsItem*> items = scene->items(QRectF(pos - QPointF(1,1), 
QSize(3,3)));

foreach(QGraphicsItem *item, items)
     if (item->type() > QGraphicsItem::UserType)
     return item;
 return 0;
  }
 bool MainWindow::eventFilter(QObject *o, QEvent *e)
  {
 QGraphicsSceneMouseEvent *me = (QGraphicsSceneMouseEvent*) e;

 switch ((int) e->type()){

 case QEvent::GraphicsSceneMousePress:{

 switch ((int) me->button()){

  case Qt::RightButton:{

     QGraphicsItem *item = itemAt(me->scenePos());

     if (item && item->type() == Block::Type){
         x=item->scenePos().x();
         y=item->scenePos().y();
        showContextMenu(item->scenePos().toPoint());
      }
   break;
  }
  }
  break;
  }
 }
 return QObject::eventFilter(o, e);
 }
void MainWindow::showContextMenu(const QPoint &pos)
{
Menu= new QMenu("Menu");
Submenu=Menu->addMenu(QIcon(":/img/pix.png"),"Pix");
Picture =Submenu->addAction(QIcon(":/img/pix.png"),"Pix");
connect(Picture, SIGNAL(triggered()), this, SLOT(addPixBlock()));
Menu->exec(QCursor::pos());
}
void MainWindow::addPixBlock()
{
QPixmap pixmap(":/img/pix.png");
pix = scene->addPixmap(pixmap.scaled(70,50));
pix->setPos(x,y);
}

block.h

#ifndef BLOCK_H
#define BLOCK_H
#include <QGraphicsPathItem>
class QGraphicsSceneMouseEvent;
class Block : public QGraphicsPathItem
{
public:
enum { Type = QGraphicsItem::UserType + 3 };
int type() const { return Type; }
Block(QGraphicsItem *parent = 0);
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget 
*widget);
bool eventFilter(QObject *, QEvent *);
};
#endif // BLOCK_H

Block.cpp

#include "block.h"
#include <QPainter>
#include <QtWidgets>
class QGraphicsSceneMouseEvent;
Block::Block(QGraphicsItem *parent)
         : QGraphicsPathItem(parent)
{
QPainterPath p;
//<->,|,<->,|,roundness
p.addRoundedRect(0,0,80,50, 5, 5);
setPath(p);
setAcceptDrops(true);
setAcceptedMouseButtons(Qt::LeftButton);
}
void Block::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, 
QWidget *widget)
{
Q_UNUSED(option)
Q_UNUSED(widget)
painter->setPen(QPen(QColor(67, 141, 220)));
painter->setBrush(QColor(67, 141, 220,100));
painter->drawPath(path());
}

1 个答案:

答案 0 :(得分:1)

首先,如果您想将QGraphicsPixmapItem放在另一个项目的顶部,更好的选择是将其设置为parentItem

另一方面,我们可以使用事件过滤器,但在这种情况下更好的选择是实现自定义QGraphicsScene,当按下左键时,它允许拖动项目,为此我们使用{ {1}}我们传递项目的数据,然后我们覆盖事件QDrag,我们将获取该项目并建立新的父项。

<强> graphicsscene.h

dropEvent

<强> graphicsscene.cpp

#ifndef GRAPHICSSCENE_H
#define GRAPHICSSCENE_H

#include <QGraphicsScene>

class QMenu;
class QAction;

class GraphicsScene : public QGraphicsScene
{
public:
    using QGraphicsScene::QGraphicsScene;

protected:
    void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
    void dropEvent(QGraphicsSceneDragDropEvent *event) override;

private:
    QGraphicsPixmapItem *findPixmapItem(QGraphicsItem *item);
    void createDrag(const QPointF &pos, QWidget *widget, QGraphicsItem *item);
    void showContextMenu(const QPointF &pos);
    void addPixBlock(QGraphicsItem *item);

    QMenu *menu;
    QMenu *submenu;
    QAction *picture;
    QGraphicsPixmapItem *pix;
};

#endif // GRAPHICSSCENE_H

然后我们建立新场景并添加#include "graphicsscene.h" #include <QDrag> #include <QGraphicsItem> #include <QGraphicsSceneMouseEvent> #include <QMenu> #include <QMimeData> #include <QWidget> void GraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event) { auto its = items(QRectF(event->scenePos() - QPointF(1,1), QSize(3,3))); auto val = std::find_if(its.constBegin(), its.constEnd(), [](auto const& it){ return it->type() > QGraphicsItem::UserType; }); if(val == its.constEnd()) return; if(event->button() == Qt::RightButton){ showContextMenu(event->scenePos()); } else{ createDrag(event->scenePos(), event->widget(), *val); } } void GraphicsScene::dropEvent(QGraphicsSceneDragDropEvent *event) { QByteArray byteArray = event->mimeData()->data("Item"); QGraphicsPixmapItem * item = *reinterpret_cast<QGraphicsPixmapItem**>(byteArray.data()); QGraphicsItem *item_parent = itemAt(event->scenePos(), QTransform()); item->setParentItem(item_parent); } QGraphicsPixmapItem *GraphicsScene::findPixmapItem(QGraphicsItem *item){ auto chs = item->childItems(); auto val = std::find_if(chs.constBegin(), chs.constEnd(), [](auto const& it){ return static_cast<QGraphicsPixmapItem *>(it) != Q_NULLPTR; }); return val == chs.constEnd() ? Q_NULLPTR : static_cast<QGraphicsPixmapItem *>(*val); } void GraphicsScene::createDrag(const QPointF &pos, QWidget *widget, QGraphicsItem *item){ QGraphicsPixmapItem *pix = findPixmapItem(item); if(pix == Q_NULLPTR) return; QByteArray byteArray(reinterpret_cast<char*>(&pix),sizeof(QGraphicsPixmapItem*)); QDrag *drag = new QDrag(widget); QMimeData * mimeData = new QMimeData; mimeData->setData("Item",byteArray); drag->setMimeData(mimeData); drag->setHotSpot(pos.toPoint()-pix->scenePos().toPoint()); drag->setPixmap(pix->pixmap()); drag->start(); } void GraphicsScene::showContextMenu(const QPointF &pos) { QGraphicsItem *item = itemAt(pos, QTransform()); menu= new QMenu("Menu"); submenu = menu->addMenu(QIcon(":/img/pix.png"),"Pix"); picture = submenu->addAction(QIcon(":/img/pix.png"),"Pix"); connect(picture, &QAction::triggered, [item, this](){ addPixBlock(item); }); menu->exec(QCursor::pos()); } void GraphicsScene::addPixBlock(QGraphicsItem *item) { if(findPixmapItem(item)) return; QPixmap pixmap(":/img/pix.png"); pix = addPixmap(pixmap.scaled(70,50)); if(pix->parentItem() != item) pix->setParentItem(item); } s。

完整示例可在以下link

中找到