在两对QGraphicsScene / QGraphicsView之间拖放QGraphicsItem [英] Drag and drop of QGraphicsItem between two pairs of QGraphicsScene/QGraphicsView

查看:246
本文介绍了在两对QGraphicsScene / QGraphicsView之间拖放QGraphicsItem的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个主窗口的应用程序,其中我创建一个 QGraphicsScene 这样:

I have an application with a mainwindow in which I create a QGraphicsScene like this:

DiagramWindow::DiagramWindow()
{
    scene = new QGraphicsScene(0, 0, 600, 500);

然后在同一个程序中,我用另一个 (不同的)QGraphicsScene。这两个场景都有各自的QGraphicsView,并且我使用相同的自定义类在每个场景/窗口中绘制QGraphicsItem。

Then on the same program, I'm calling another window with another (different)QGraphicsScene. Both of these scenes have their respective QGraphicsViews and I use the same custom class to draw QGraphicsItem in each scene/window.

现在我试图实现拖放在两个场景/窗口之间使用这个,我得到一个效果,我认为是类似/相同于这个问题
。基本上,当我将QGraphicsItem从第二个窗口/场景拖动到主窗口时,它不会在场景中触发事件,它在主要的触发器窗口的工具栏/边框。

Now I'm trying to implement drag and drop between the two scenes/windows using this and I'm getting an effect that I think is similar/the same as in this SO question . Basically, when I drag a QGraphicsItem from the second window/scene to the main window, it does not trigger the event on the scene, BUT it does trigger in in the main window's toolbar/ borders.

我的事件处理功能是:

void DiagramWindow::dragEnterEvent(QDragEnterEvent *event)
{
    qDebug() << "I'm on the main window!";

    event->acceptProposedAction();
}

void DiagramWindow::dropEvent(QDropEvent *event)
{
    event->acceptProposedAction();
    qDebug() << "got a drop!";
}

根据答案,我将不得不 setAcceptDrops()在QGraphicsScene(这是不可能的),所以这个技巧似乎是重载的 QGraphicsScene :: dragMoveEvent()。因为我没有一个特定的类为我的QGraphicsScene(只是为它的父 DiagramWindow ),我不知道如何写一个函数来定位场景具体 dragMoveEvent()

According to the answers there, I would have to setAcceptDrops() in a QGraphicsScene (which is not possible), so the trick seems to be to overload the QGraphicsScene::dragMoveEvent(). Since I don't have a specific class for my QGraphicsScene (just for it's parent DiagramWindow), I don't know how I can write a function to target the scene's specific dragMoveEvent().

问题1 我希望我可以做某事如:

QUESTION 1 I was hoping I could do something like:

DiagramWindow->scene::dragMoveEvent()
{
    ...
}

但当然这是不可能的。我对C ++ / Qt来说真的很新,一般的工作流/语法动态仍然排除了我。如何将QGraphicsScene定位到MainWindow内以编写事件处理函数?

But of course this is not possible. I'm really new to C++/Qt and the general workflow/syntax dynamics still ellude me. How can I target the QGraphicsScene inside my MainWindow to write the event handling function?

QUESTION 2 另外,我注意到通过重写这些事件处理功能,我(显然)失去了在主窗口中的大部分功能 - 选择和移动QGraphicsItems不再有效。有没有可以让这些事件触发,只有事件发生在第二个窗口?我看过 QDrag-> source( ) 但是,如果事件发生在第二个窗口,但是我没有得到它的工作原理,就像这样,如果事情发生在第二个窗口中,那么这样做,否则,继续做你在做的事情 - 我不知道什么是...:)

QUESTION 2 Also, I noticed that by rewriting these event handling functions, I (obviously) lost most of the funcionality I had in the main window - selecting and moving around the QGraphicsItems no longer works. Is there anyway I can make these events trigger only if the events are being originated in the second window? I have looked at QDrag->source() but I'm not getting how it works either - something like, if the events originate in the second window, do this, else, keep doing what you were doing before - which I don't actually know what is... :)

推荐答案

Question1

Question1

如果图窗口接收到该事件,并希望通过当前显示的场景接收该事件通过视图,那么你应该做的是将事件传递给视图,将其转换为 QGraphicsSceneDragDropEvent 并将其重定向到现场:

If the event is received by the diagramWindow, and want it receive by the scene which is currently displayed by a view, then what you should do is pass the event to the view, that will convert it to a QGraphicsSceneDragDropEvent and redirect it to the scene:

void DiagramWindow::dragMoveEvent(event)
{
    view->dragMoveEvent(event);
}

问题2

对Drag事件不太了解,因此无法帮助,但是要根据if语句获取以前的行为,您应该执行以下操作:

Don't know much about Drag event so can't help, but to get the previous behaviour depending on a if statement, you should do:

void MyDerivedClass::myEvent(event)
{
    if(...)
        // do specific behaviour
    else
        QBaseClass::myEvent(event); // default behaviour
}

假设你的类 MyDerivedClass (在你的情况下, DiagramWindow )继承自Qt类 QBaseClass (在你的情况下, code> QMainWindow ?),您要覆盖的事件方法是 myEvent()(在您的情况下 dragMoveEvent )。

assuming your class MyDerivedClass(in your case, DiagramWindow) inherits from the Qt class QBaseClass (in your case, QMainWindow?), and the event method you want to override is myEvent() (in your case, dragMoveEvent).

工作示例:

我不太清楚你的类DiagramWindow是什么,但这里是一个工作的例子,应该给你所有必要的想法,使其在你的情况下工作。我建议你从这个工作示例开始,并修改它以获得你需要的。

I don't know exacly what your class DiagramWindow is, but here is a working example that should give you all the necessary ideas to make it work in your case. I suggest you start from this working example, and modify it to get what you need.

main.cpp:

#include <QApplication>

#include "Scene.h"
#include "View.h"

int main(int argc, char * argv[])
{
    QApplication app(argc,argv);

    Scene * scene1 = new Scene(1);
    View * view1 = new View(scene1, 1);

    Scene * scene2 = new Scene(2);
    View * view2 = new View(scene2,2);

    view1->show();
    view2->show();
    return app.exec();
}

Scene.h:

#ifndef SCENE_H
#define SCENE_H

#include <QGraphicsScene>
#include <QGraphicsEllipseItem>

class Item;

class Item: public QGraphicsEllipseItem
{
public:
    Item(int x,int y);

protected:
    void mousePressEvent(QGraphicsSceneMouseEvent *event);
};


class Scene: public QGraphicsScene
{
public:
    Scene(int i);

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

    int i;
};

#endif

Scene.cpp:

Scene.cpp:

#include "Scene.h"

#include <QtDebug>
#include <QGraphicsSceneMouseEvent>
#include <QDrag>
#include <QMimeData>

Item::Item(int x, int y) : QGraphicsEllipseItem(x,y,50,50) {}

void Item::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    qDebug() << "item mouse press";

    // Create the mime  data that will be transfered  from one scene
    // to another
    QMimeData * mimeData = new QMimeData;

    // In our case, the data will be the address of the item.
    //
    // Note: This is  UNSAFE, and just for the  sake of example. The
    // good way to do it is to create your own mime type, containing
    // all the information necessary to recreate an identical Item.
    // 
    // This  is because  drag  and  drop is  meant  to work  between
    // applications, and the address  of your item is not accessible
    // by  other  applications   (deferencing  it  would  produce  a
    // segfault). It  works fine  in this case  since you  perform a
    // drag  and   drop  between  different  windows   of  the  same
    // application.
    Item * item = this;
    QByteArray byteArray(reinterpret_cast<char*>(&item),sizeof(Item*));
    mimeData->setData("Item",byteArray);

    // start the event
    QDrag * drag = new QDrag(event->widget());
    drag->setMimeData(mimeData);
    drag->start();
}

Scene::Scene(int i) : i(i)
{
    Item * item = new Item(100+100*i,100);
    addItem(item);
}           

void Scene::dragEnterEvent ( QGraphicsSceneDragDropEvent * event )
{
    qDebug() << "scene" << i << "drag enter"; 
}

void Scene::dragLeaveEvent ( QGraphicsSceneDragDropEvent * event )
{
    qDebug() << "scene" << i << "drag leave"; 
}

void Scene::dragMoveEvent ( QGraphicsSceneDragDropEvent * event )
{
    qDebug() << "scene" << i << "drag move";
}


void Scene::dropEvent ( QGraphicsSceneDragDropEvent * event )
{
    qDebug() << "scene" << i << "drop";

    // retrieve the address of the item from the mime data
    QByteArray byteArray = event->mimeData()->data("Item");
    Item * item = *reinterpret_cast<Item**>(byteArray.data());

    // add the item  to the scene (automatically remove  it from the
    // other scene)
    addItem(item);
}

View.h:

#ifndef VIEW_H
#define VIEW_H

#include <QGraphicsView>
#include "Scene.h"

class View: public QGraphicsView
{
public:
    View(Scene * scene, int i);

protected:
    virtual void dragEnterEvent ( QDragEnterEvent * event );
    virtual void dragLeaveEvent ( QDragLeaveEvent * event );
    virtual void dragMoveEvent ( QDragMoveEvent * event );
    virtual void dropEvent ( QDropEvent * event );

private:
    Scene * scene_;
    int i;
};

#endif

View.cpp:

#include "View.h"
#include <QtDebug>

View::View(Scene * scene, int i) :
    QGraphicsView(scene),
    scene_(scene),
    i(i)
{
}

void View::dragEnterEvent ( QDragEnterEvent * event )
{
    qDebug() << "view" << i << "drag enter";
    QGraphicsView::dragEnterEvent(event);
}

void View::dragLeaveEvent ( QDragLeaveEvent * event )
{
    qDebug() << "view" << i <<"drag leave";
    QGraphicsView::dragLeaveEvent(event);
}

void View::dragMoveEvent ( QDragMoveEvent * event )
{
    qDebug() << "view" << i << "drag move";
    QGraphicsView::dragMoveEvent(event);
}

void View::dropEvent ( QDropEvent * event )
{
    qDebug() << "view" << i << "drop";
    QGraphicsView::dropEvent(event);
}

在您的情况下,如果需要显式调用 DiagramWindow 中查看> someDragDropEvent(event),那么您只需要更改 protected: public:。但我不认为这是必要的,只需尝试而不用重新实现 DiagramWindow 中的拖放事件,它应该自动调用你的看法。

In your case, if you need to explicitly call view->someDragDropEvent(event) from your DiagramWindow, then you just have to change the protected: to public:. But I don't think it is necessary, just try without reimplementing the drag and drop event in DiagramWindow, and it should automatically call the one of your view.

这篇关于在两对QGraphicsScene / QGraphicsView之间拖放QGraphicsItem的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆