Qt - 使用图形视图框架进行拖放

发布于 2024-08-30 11:08:42 字数 3963 浏览 8 评论 0原文

我正在尝试使用图形框架制作一个简单的可拖动项目。以下是我到目前为止所做的代码:

Widget 类:

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);
    ~Widget();

};

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    DragScene *scene = new DragScene();
    DragView *view = new DragView();
    QHBoxLayout *layout = new QHBoxLayout();

    DragItem *item = new DragItem();
    view->setAcceptDrops(true);
    scene->addItem(item);
    view->setScene(scene);
    layout->addWidget(view);
    this->setLayout(layout);

}

Widget::~Widget()
{
}

DragView 类:

class DragView : public QGraphicsView
{
public:
    DragView(QWidget *parent = 0);
};

DragView::DragView(QWidget *parent) : QGraphicsView(parent)
{
    setRenderHints(QPainter::Antialiasing);
}

DragScene 类:

class DragScene : public QGraphicsScene
{
public:
    DragScene(QObject* parent = 0);

protected:
    void dragEnterEvent(QGraphicsSceneDragDropEvent *event);
    void dragMoveEvent(QGraphicsSceneDragDropEvent *event);
    void dragLeaveEvent(QGraphicsSceneDragDropEvent *event);
    void dropEvent(QGraphicsSceneDragDropEvent *event);
};

DragScene::DragScene(QObject* parent) : QGraphicsScene(parent)
{
}

void DragScene::dragEnterEvent(QGraphicsSceneDragDropEvent *event){
}

void DragScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event){
}

void DragScene::dragLeaveEvent(QGraphicsSceneDragDropEvent *event){
}

void DragScene::dropEvent(QGraphicsSceneDragDropEvent *event){
    qDebug() << event->pos();
    event->acceptProposedAction();
    DragItem *item = new DragItem();
    this->addItem(item);
    // item->setPos(event->pos()); before badgerr's tip
    item->setPos(event->scenePos());
}

DragItem 类:

class DragItem : public QGraphicsItem
{
public:
    DragItem(QGraphicsItem *parent = 0);
    QRectF boundingRect() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);

protected:
    void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
    void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
    void mousePressEvent(QGraphicsSceneMouseEvent *event);
    void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
};

DragItem::DragItem(QGraphicsItem *parent) : QGraphicsItem(parent)
{
    setFlag(QGraphicsItem::ItemIsMovable);
}

QRectF DragItem::boundingRect() const{
    const QPointF *p0 = new QPointF(-10,-10);
    const QPointF *p1 = new QPointF(10,10);
    return QRectF(*p0,*p1);
}

void DragItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){
    if(painter == 0)
        painter = new QPainter();
    painter->drawEllipse(QPoint(0,0),10,10);
}

void DragItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event){

}

void DragItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event){
}

void DragItem::mousePressEvent(QGraphicsSceneMouseEvent *event){
    QMimeData* mime = new QMimeData();
    QDrag* drag = new QDrag(event->widget());
    drag->setMimeData(mime);
    drag->exec();
}

void DragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event){
}

main.cpp 实例化一个 Widget 并显示它。当我尝试拖动圆圈时,无论我在何处释放拖动,应用程序都会在原始圆圈上创建另一个圆圈。每次拖动结束时,DragScene 的 dropEvent() 中的 qDebug() 都会显示 QPointF(0,0)。我很难准确地理解我必须做什么,我应该子类化哪些类,需要重写哪些方法,才能使这项工作正常进行。关于此的文档不是很详细。我想知道如何实现这项工作,除了官方文档之外,是否还有其他更全面的资源来了解图形视图框架(顺便说一句,这非常好,但如果有更详细的文档,那就太好了有关该主题的论文)。

编辑:

按照 badrr 的建议,我用 item->scenePos() 替换了 DragScene::dropEvent() 中的 item->pos() ,现在放置事件在放置站点中创建了一个新的圆圈,这或多或少是什么我想要。但原始圆圈仍然存在,并且在拖动过程中,该项目不跟随鼠标光标。

QGraphicsSceneDragDropEvent 文档说 pos() 应该返回相对于发送事件的视图的光标位置,除非我弄错了,否则不应始终为 (0,0)。诡异的。

我在论坛帖子中读到,您可以使用 QDrag::setPixMap() 在拖动过程中显示某些内容,在示例中我看到图片被设置为像素图,但如何使像素图就像图形项一样我该拖着走吗?

I'm trying to make a simple draggable item using the graphics framework. Here's the code for what I did so far:

Widget class:

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);
    ~Widget();

};

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    DragScene *scene = new DragScene();
    DragView *view = new DragView();
    QHBoxLayout *layout = new QHBoxLayout();

    DragItem *item = new DragItem();
    view->setAcceptDrops(true);
    scene->addItem(item);
    view->setScene(scene);
    layout->addWidget(view);
    this->setLayout(layout);

}

Widget::~Widget()
{
}

DragView class:

class DragView : public QGraphicsView
{
public:
    DragView(QWidget *parent = 0);
};

DragView::DragView(QWidget *parent) : QGraphicsView(parent)
{
    setRenderHints(QPainter::Antialiasing);
}

DragScene class:

class DragScene : public QGraphicsScene
{
public:
    DragScene(QObject* parent = 0);

protected:
    void dragEnterEvent(QGraphicsSceneDragDropEvent *event);
    void dragMoveEvent(QGraphicsSceneDragDropEvent *event);
    void dragLeaveEvent(QGraphicsSceneDragDropEvent *event);
    void dropEvent(QGraphicsSceneDragDropEvent *event);
};

DragScene::DragScene(QObject* parent) : QGraphicsScene(parent)
{
}

void DragScene::dragEnterEvent(QGraphicsSceneDragDropEvent *event){
}

void DragScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event){
}

void DragScene::dragLeaveEvent(QGraphicsSceneDragDropEvent *event){
}

void DragScene::dropEvent(QGraphicsSceneDragDropEvent *event){
    qDebug() << event->pos();
    event->acceptProposedAction();
    DragItem *item = new DragItem();
    this->addItem(item);
    // item->setPos(event->pos()); before badgerr's tip
    item->setPos(event->scenePos());
}

DragItem class:

class DragItem : public QGraphicsItem
{
public:
    DragItem(QGraphicsItem *parent = 0);
    QRectF boundingRect() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);

protected:
    void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
    void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
    void mousePressEvent(QGraphicsSceneMouseEvent *event);
    void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
};

DragItem::DragItem(QGraphicsItem *parent) : QGraphicsItem(parent)
{
    setFlag(QGraphicsItem::ItemIsMovable);
}

QRectF DragItem::boundingRect() const{
    const QPointF *p0 = new QPointF(-10,-10);
    const QPointF *p1 = new QPointF(10,10);
    return QRectF(*p0,*p1);
}

void DragItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){
    if(painter == 0)
        painter = new QPainter();
    painter->drawEllipse(QPoint(0,0),10,10);
}

void DragItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event){

}

void DragItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event){
}

void DragItem::mousePressEvent(QGraphicsSceneMouseEvent *event){
    QMimeData* mime = new QMimeData();
    QDrag* drag = new QDrag(event->widget());
    drag->setMimeData(mime);
    drag->exec();
}

void DragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event){
}

main.cpp instantiates a Widget and shows it. When I try to drag the circle, the app just creates another circle over the original one, regardless of where I release the drag. qDebug() in DragScene's dropEvent() shows QPointF(0,0) everytime the drag ends. I'm having a hard time trying to understand exactly what I have to do, which classes I should subclass, which methods needs to be overriden, to make this work. The documentation on this isn't very detailed. I'd like to know how to make this work, and if there's some other, more comprehensive resource to learn about the graphics view framework, besides the official documentation (which is excellent btw, but it would be great if there was a more detailed treatise on the subject).

EDIT:

Following badgerr's advice, I replaced item->pos() in DragScene::dropEvent() with item->scenePos(), now the drop event creates a new circle in the drop site, which is more or less what I wanted. But the original circle is still in place, and while the drag is in progress, the item doesn't follow the mouse cursor.

The QGraphicsSceneDragDropEvent documentation says that pos() should return the cursor position in relation to the view that sent the event, which, unless I got it wrong, shouldn't be (0,0) all the time. Weird.

I've read in a forum post that you can use QDrag::setPixMap() to show something during the drag, and in examples I've seen pictures being set as pixmaps, but how do I make the pixmap just like the graphics item I'm supposed to be dragging?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

忆梦 2024-09-06 11:08:42

Qt Assistant 有一个名为“拖放机器人示例”的示例,它似乎使用了 QDrag 方法,我不知道您是否已经看过该示例。

编辑:快速观察一下,您似乎在 DropEvent 中创建一个新的 DragItem,而不是使用事件本身的 mimeData() ,并且由于您的项目在 0,0 处绘制自身,因此可能会解释为什么无论您将 DragItem 放在何处,该位置都会出现一个新的。


当我编写与此类似的图形拖动内容时,我采用了稍微不同的方式。也许它会对你有所帮助:

我没有使用 QDrag 的东西,而是只使用了 QGraphicsItem 的 mousePressEvent、mouseReleaseEvent 和 mouseMoveEvent 函数。 的过程

  • 鼠标按下/释放设置一个指示拖动状态的标志,移动遵循调用prepareGeometryChange()
  • ;更新QGraphicsItem的边界(我的boundingRect()函数返回这些边界。我所有的图形项边界都在QGraphicsScene空间中)
  • 调用update();

然后在我的paint()函数中,我使用boundingRect()绘制一个形状。

抱歉,我没有可以分享的代码示例,如果有时间我会敲一个。

There is an example with Qt Assistant called the "Drag and Drop Robot Example" which appears to use the QDrag method, I don't know if you've had a look at that already.

edit: Just a quick observation, you appear to be creating a new DragItem in your DropEvent, instead of using the mimeData() of the event itself, and since your item draws itself at 0,0, that might explain why you have a new one appearing at that position regardless of where you drop your DragItem.


When I wrote a graphics dragging thing similar to this, I went about it a slightly different way. Maybe it will help you:

Instead of using the QDrag stuff, I used only the mousePressEvent, mouseReleaseEvent, and mouseMoveEvent functions of QGraphicsItem. The mouse press/release set a flag indicating the drag state, and move followed a process of

  • call prepareGeometryChange();
  • update the bounds of the QGraphicsItem (my boundingRect() function returns these bounds. All my graphics item bounds are in QGraphicsScene space)
  • call update();

Then in my paint() function I draw a shape using the boundingRect().

Sorry I don't have a code sample to share, I'll knock one up if I get time.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文