I have an application with a mainwindow in which I create a QGraphicsScene like this:
我有一个主窗口的应用程序,在其中我创建了一个QGraphicsScene:
DiagramWindow::DiagramWindow()
{
scene = new QGraphicsScene(0, 0, 600, 500);
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.
然后在同一个程序中,我调用另一个窗口与另一个(不同的)QGraphicsScene。这两个场景都有各自的qgraphicsview,我使用同一个自定义类在每个场景/窗口中绘制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.
现在,我尝试在两个场景/窗口之间实现拖放操作,我得到了一个我认为与这个问题相似的效果。基本上,当我将一个QGraphicsItem从第二个窗口/场景拖动到主窗口时,它不会触发场景中的事件,但是它会触发主窗口的工具栏/边框。
My event handling functions are:
我的事件处理功能是:
void DiagramWindow::dragEnterEvent(QDragEnterEvent *event)
{
qDebug() << "I'm on the main window!";
event->acceptProposedAction();
}
and
和
void DiagramWindow::dropEvent(QDropEvent *event)
{
event->acceptProposedAction();
qDebug() << "got a drop!";
}
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()
.
根据这里的答案,我必须在一个QGraphicsScene(不可能)中设置acceptdrop(),所以这个技巧似乎是重载QGraphicsScene::dragMoveEvent()。由于我没有为我的QGraphicsScene设置一个特定的类(仅为它的父图窗口),我不知道如何编写一个函数来针对场景的特定dragMoveEvent()。
QUESTION 1 I was hoping I could do something like:
问题1我希望我能做点什么:
DiagramWindow->scene::dragMoveEvent()
{
...
}
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?
当然,这是不可能的。我对c++ /Qt真的很陌生,但我仍然无法理解一般的工作流/语法动态。如何在主窗口内锁定QGraphicsScene,以写入事件处理函数?
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... :)
问题2,我注意到,通过重写这些事件处理函数,我(很明显)失去了在主窗口中所拥有的大多数功能——选择和在QGraphicsItems中移动不再有效。如果事件发生在第二个窗口中,我是否可以让这些事件触发?我看了QDrag->源代码(),但我也不知道它是如何工作的——比如,如果事件发生在第二个窗口,那么就这样做,否则,继续做你以前做过的事情——我实际上不知道什么是……:)
1 个解决方案
#1
5
Question1
问题1
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:
如果该事件是由diagramWindow接收的,并希望它接收当前视图显示的场景,那么您应该做的是将事件传递给视图,该视图将它转换为QGraphicsSceneDragDropEvent并将其重定向到场景:
void DiagramWindow::dragMoveEvent(event)
{
view->dragMoveEvent(event);
}
Question 2
问题2
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:
对于拖拽事件不太了解,因此无法帮助,但是要根据if语句获得之前的行为,您应该这样做:
void MyDerivedClass::myEvent(event)
{
if(...)
// do specific behaviour
else
QBaseClass::myEvent(event); // default behaviour
}
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
).
假设您的类MyDerivedClass(在您的情况下,DiagramWindow)继承了Qt类QBaseClass(在您的案例中是QMainWindow?),您想要重写的事件方法是myEvent()(在您的例子中,是dragMoveEvent)。
Working example:
工作的例子:
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:
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:
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:
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:
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);
}
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.
在您的案例中,如果您需要显式地调用视图—从您的图表窗口中显示的某个dragdropevent(事件),那么您只需更改受保护的:到public:。但我不认为有必要,只需尝试在DiagramWindow中重新实现拖放事件,它就会自动调用您的视图。
#1
5
Question1
问题1
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:
如果该事件是由diagramWindow接收的,并希望它接收当前视图显示的场景,那么您应该做的是将事件传递给视图,该视图将它转换为QGraphicsSceneDragDropEvent并将其重定向到场景:
void DiagramWindow::dragMoveEvent(event)
{
view->dragMoveEvent(event);
}
Question 2
问题2
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:
对于拖拽事件不太了解,因此无法帮助,但是要根据if语句获得之前的行为,您应该这样做:
void MyDerivedClass::myEvent(event)
{
if(...)
// do specific behaviour
else
QBaseClass::myEvent(event); // default behaviour
}
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
).
假设您的类MyDerivedClass(在您的情况下,DiagramWindow)继承了Qt类QBaseClass(在您的案例中是QMainWindow?),您想要重写的事件方法是myEvent()(在您的例子中,是dragMoveEvent)。
Working example:
工作的例子:
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:
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:
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:
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:
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);
}
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.
在您的案例中,如果您需要显式地调用视图—从您的图表窗口中显示的某个dragdropevent(事件),那么您只需更改受保护的:到public:。但我不认为有必要,只需尝试在DiagramWindow中重新实现拖放事件,它就会自动调用您的视图。