Qt 在两对QGraphicscene/QGraphicsView之间拖放QGraphicsItem

Qt 在两对QGraphicscene/QGraphicsView之间拖放QGraphicsItem,qt,drag-and-drop,qgraphicsview,qgraphicsscene,Qt,Drag And Drop,Qgraphicsview,Qgraphicsscene,我有一个带有主窗口的应用程序,我在其中创建了一个如下所示的主窗口: DiagramWindow::DiagramWindow() { scene = new QGraphicsScene(0, 0, 600, 500); 然后在同一个程序中,我用另一个(不同的)Qgraphicscene调用另一个窗口。这两个场景都有各自的QGraphicsView,我使用相同的自定义类在每个场景/窗口中绘制QGraphicsItem 现在,我正试图在两个场景/窗口之间使用,我得到了一个我认为与中类似/

我有一个带有主窗口的应用程序,我在其中创建了一个如下所示的主窗口:

DiagramWindow::DiagramWindow()
{
    scene = new QGraphicsScene(0, 0, 600, 500);
然后在同一个程序中,我用另一个(不同的)Qgraphicscene调用另一个窗口。这两个场景都有各自的QGraphicsView,我使用相同的自定义类在每个场景/窗口中绘制QGraphicsItem

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

我的事件处理功能包括:

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

    event->acceptProposedAction();
}
但这当然是不可能的。我对C++/Qt真的很陌生,一般的工作流/语法动态仍然困扰着我。如何在主窗口中以QGraphicscene为目标来编写事件处理函数


问题2此外,我注意到,通过重写这些事件处理函数,我(显然)失去了主窗口中的大部分功能—选择和移动QGraphics站点不再有效。是否只有在第二个窗口中发生事件时,我才能触发这些事件?我已经看过了,但我也不知道它是如何工作的——比如,如果事件起源于第二个窗口,那么就这样做,否则,继续做你以前做过的事情——实际上我不知道什么是……:)

问题1

如果diagramWindow接收到事件,并且希望通过当前由
视图显示的
场景
接收该事件,则应将事件传递到视图,该视图将其转换为
QGraphicsCendragProperty
,并将其重定向到场景:

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

对拖动事件了解不多,因此无法提供帮助,但要根据if语句获得之前的行为,您应该执行以下操作:

void MyDerivedClass::myEvent(event)
{
    if(...)
        // do specific behaviour
    else
        QBaseClass::myEvent(event); // default behaviour
}
假设您的类
MyDerivedClass
(在您的例子中,
DiagramWindow
)继承自Qt类
QBaseClass
(在您的例子中,
QMainWindow
?),并且您想要覆盖的事件方法是
myEvent()
(在您的例子中,
dragmovevent

工作示例:

我不太清楚你的类DiagramWindow是什么,但这里有一个工作示例,它应该给你所有必要的想法,让它在你的案例中工作。我建议您从这个工作示例开始,并对其进行修改以获得所需的内容

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”
#包括“View.h”
int main(int argc,char*argv[])
{
QApplication应用程序(argc、argv);
场景*scene1=新场景(1);
视图*view1=新视图(场景1,1);
场景*scene2=新场景(2);
视图*view2=新视图(场景2,2);
视图1->show();
视图2->show();
返回app.exec();
}
场景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
#如果场景不可用#
#定义场景
#包括
#包括
类别项目;
类别项:公共QGraphicsSellipseitem
{
公众:
项目(整数x,整数y);
受保护的:
无效鼠标压力事件(QGraphicsSceneMouseEvent*事件);
};
课堂场景:公共Qgraphicscene
{
公众:
场景(int i);
受保护的:
虚拟无效dragEnterEvent(QGraphicsCeneDragDropEvent*事件);
虚拟无效dragLeaveEvent(QGraphicsCeneDragDropEvent*事件);
虚拟无效dragMoveEvent(QGraphicsSceneDragDropEvent*事件);
虚拟void dropEvent(QGraphicsSceneDragDropEvent*事件);
int i;
};
#恩迪夫
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);
}
#包括“Scene.h”
#包括
#包括
#包括
#包括
Item::Item(intx,inty):QGraphicsEllipseItem(x,y,50,50){
无效项::MousePresseEvent(QGraphicsSceneMouseEvent*事件)
{
qDebug()设置数据(“项”,byteArray);
//启动活动
QDrag*drag=newqdrag(事件->小部件());
拖动->设置mimeData(mimeData);
拖动->开始();
}
场景::场景(inti):i(i)
{
项目*项目=新项目(100+100*i,100);
增编(项目);
}           
无效场景::dragEnterEvent(QGraphicsSceneDragDropEvent*事件)
{

qDebug()关于问题2的更多信息含义:您对第一个问题的回答不起作用,因为QGraphicsCene的
dragMoveEvent
需要
QGraphicsCeneDragPropertent
类型的事件,而DiagramWindow的
dragMoveEvent
类型是
QDragEnterEvent
。因此,似乎需要某种转换。任何想法?好的,事实上,我检查了文档。所以你要做的是调用
视图->dragMoveEvent()
,这将进行转换(从鼠标坐标转换为场景坐标),并重定向到其附加的QGraphicscene。好的,是的。只需将其公开;-)如果使用直接的QGraphicsView,这意味着使用派生类,在其中重新实现事件方法,但将其声明为公共而不是受保护。在重新实现中,您只需调用基本方法,如我回答的第二部分所述,without the“if”。或者,您可以保护该方法,但可以将DiagramWindow声明为继承QGraphicsView的类的朋友类。@Joum:不,您肯定不需要自己重新实现,这并不难。我有一个工作示例来告诉您如何做。希望对您有所帮助:)
#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
#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);
}
#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
#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);
}