检测所有子控件上的拖放
Detect Drag on Drop over all Child QWidgets
我正在尝试在我的整个应用程序中实现拖放行为,我想在发生拖放时执行一些操作,无论在 MainWindow 的哪个位置。我面临的问题是,在我的 MainWindow 中,我有一个包含 QGraphicsView 的 Widget,它又包含一个 QGraphicsScene,我可以通过 EventFilter 检测应用程序中任何地方的放置,除了在视图和场景中。是否有可能实现某种我可以从 MainWindow 检测到的全局拖放行为?我试图避免在我所有可见的小部件中传播逻辑。
这是我的 MainWindow 中的拖放逻辑,如前所述,适用于所有不在 View/Scene:
上发生的拖放
void MainWindow::dropEvent(QDropEvent *event)
{
auto pixmap = QPixmap(event->mimeData()->urls().first().toString().remove("file://"));
if(!pixmap.isNull()) {
load(pixmap);
}
event->acceptProposedAction();
}
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
if (event->mimeData()->hasUrls()) {
event->acceptProposedAction();
}
}
对于 View/Scene 上的拖放,我尝试安装以下事件过滤器:
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if(event->type() == QEvent::DragEnter) {
qDebug("Enter");
} else if(event->type() == QEvent::Drop) {
qDebug("Drop");
} else if(event->type() == QEvent::GraphicsSceneDrop) {
qDebug("Scene drop");
} else if (event->type() >= 159 && event->type() <= 168) {
qDebug("Any Scene Event");
}
return QObject::eventFilter(obj, event);
}
并将它应用到 MainWindow ctor 中,我唯一检测到的是进入视图时的回车。
...
setAcceptDrops(true);
mChildWidget->installEventFilter(this);
mChildWidget->setAcceptDrops(true);
...
看来我在这里遇到了两个问题。第一个在此处 Accepting drops on a QGraphicsScene 的问题中进行了解释。 QGraphicsScene 忽略未在项目上发生的 DragAndDrops。基本上,您可以启用拖放功能,但只能单独针对每个项目,这仍然会留下未被项目覆盖的区域。这个问题的解决方案似乎是覆盖 dragMoveEvent
void MyQGprahicsScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
{
Q_UNUSED(event)
// Overriding default dragMoveEvent in order to accept drops without items under them
}
我面临的第二个问题是我试图将 eventFilter 应用于 Child 小部件,但看起来我必须将它应用于 qApp,之后一切似乎都正常,可能是因为 qApp 是top QObject,所有事件在未处理时都会落在该 QObject 上。
#include "DragAndDropHandler.h"
bool DragAndDropHandler::eventFilter(QObject *obj, QEvent *event)
{
if(event->type() == QEvent::DragEnter) {
handleDragEnter(dynamic_cast<QDragEnterEvent *>(event));
} else if(event->type() == QEvent::Drop) {
handleDrop(dynamic_cast<QDropEvent *>(event));
} else if(event->type() == QEvent::GraphicsSceneDrop) {
handleDrop(dynamic_cast<QGraphicsSceneDragDropEvent *>(event));
} else if (event->type() == QEvent::GraphicsSceneDragEnter) {
handleDragEnter(dynamic_cast<QGraphicsSceneDragDropEvent *>(event));
}
return QObject::eventFilter(obj, event);
}
void DragAndDropHandler::handleDragEnter(QDragEnterEvent *event)
{
if (event->mimeData()->hasUrls()) {
event->acceptProposedAction();
}
}
void DragAndDropHandler::handleDragEnter(QGraphicsSceneDragDropEvent *event)
{
if (event->mimeData()->hasUrls()) {
event->acceptProposedAction();
}
}
void DragAndDropHandler::handleDrop(QDropEvent *event)
{
auto path = getUrlFromMimeData(event->mimeData());
event->acceptProposedAction();
emit imageDropped(path);
}
void DragAndDropHandler::handleDrop(QGraphicsSceneDragDropEvent *event)
{
auto path = getUrlFromMimeData(event->mimeData());
event->acceptProposedAction();
emit imageDropped(path);
}
QString DragAndDropHandler::getUrlFromMimeData(const QMimeData *mimeData) const
{
return mimeData->urls().first().toString().remove("file://");
}
并且,在我的 MainWindow 的构造函数中:
setAcceptDrops(true);
qApp->installEventFilter(mDragAndDropHandler);
connect(mDragAndDropHandler, &DragAndDropHandler::imageDropped, this, &MainWindow::loadImageFromFile);
我正在尝试在我的整个应用程序中实现拖放行为,我想在发生拖放时执行一些操作,无论在 MainWindow 的哪个位置。我面临的问题是,在我的 MainWindow 中,我有一个包含 QGraphicsView 的 Widget,它又包含一个 QGraphicsScene,我可以通过 EventFilter 检测应用程序中任何地方的放置,除了在视图和场景中。是否有可能实现某种我可以从 MainWindow 检测到的全局拖放行为?我试图避免在我所有可见的小部件中传播逻辑。
这是我的 MainWindow 中的拖放逻辑,如前所述,适用于所有不在 View/Scene:
上发生的拖放void MainWindow::dropEvent(QDropEvent *event)
{
auto pixmap = QPixmap(event->mimeData()->urls().first().toString().remove("file://"));
if(!pixmap.isNull()) {
load(pixmap);
}
event->acceptProposedAction();
}
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
if (event->mimeData()->hasUrls()) {
event->acceptProposedAction();
}
}
对于 View/Scene 上的拖放,我尝试安装以下事件过滤器:
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if(event->type() == QEvent::DragEnter) {
qDebug("Enter");
} else if(event->type() == QEvent::Drop) {
qDebug("Drop");
} else if(event->type() == QEvent::GraphicsSceneDrop) {
qDebug("Scene drop");
} else if (event->type() >= 159 && event->type() <= 168) {
qDebug("Any Scene Event");
}
return QObject::eventFilter(obj, event);
}
并将它应用到 MainWindow ctor 中,我唯一检测到的是进入视图时的回车。
...
setAcceptDrops(true);
mChildWidget->installEventFilter(this);
mChildWidget->setAcceptDrops(true);
...
看来我在这里遇到了两个问题。第一个在此处 Accepting drops on a QGraphicsScene 的问题中进行了解释。 QGraphicsScene 忽略未在项目上发生的 DragAndDrops。基本上,您可以启用拖放功能,但只能单独针对每个项目,这仍然会留下未被项目覆盖的区域。这个问题的解决方案似乎是覆盖 dragMoveEvent
void MyQGprahicsScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
{
Q_UNUSED(event)
// Overriding default dragMoveEvent in order to accept drops without items under them
}
我面临的第二个问题是我试图将 eventFilter 应用于 Child 小部件,但看起来我必须将它应用于 qApp,之后一切似乎都正常,可能是因为 qApp 是top QObject,所有事件在未处理时都会落在该 QObject 上。
#include "DragAndDropHandler.h"
bool DragAndDropHandler::eventFilter(QObject *obj, QEvent *event)
{
if(event->type() == QEvent::DragEnter) {
handleDragEnter(dynamic_cast<QDragEnterEvent *>(event));
} else if(event->type() == QEvent::Drop) {
handleDrop(dynamic_cast<QDropEvent *>(event));
} else if(event->type() == QEvent::GraphicsSceneDrop) {
handleDrop(dynamic_cast<QGraphicsSceneDragDropEvent *>(event));
} else if (event->type() == QEvent::GraphicsSceneDragEnter) {
handleDragEnter(dynamic_cast<QGraphicsSceneDragDropEvent *>(event));
}
return QObject::eventFilter(obj, event);
}
void DragAndDropHandler::handleDragEnter(QDragEnterEvent *event)
{
if (event->mimeData()->hasUrls()) {
event->acceptProposedAction();
}
}
void DragAndDropHandler::handleDragEnter(QGraphicsSceneDragDropEvent *event)
{
if (event->mimeData()->hasUrls()) {
event->acceptProposedAction();
}
}
void DragAndDropHandler::handleDrop(QDropEvent *event)
{
auto path = getUrlFromMimeData(event->mimeData());
event->acceptProposedAction();
emit imageDropped(path);
}
void DragAndDropHandler::handleDrop(QGraphicsSceneDragDropEvent *event)
{
auto path = getUrlFromMimeData(event->mimeData());
event->acceptProposedAction();
emit imageDropped(path);
}
QString DragAndDropHandler::getUrlFromMimeData(const QMimeData *mimeData) const
{
return mimeData->urls().first().toString().remove("file://");
}
并且,在我的 MainWindow 的构造函数中:
setAcceptDrops(true);
qApp->installEventFilter(mDragAndDropHandler);
connect(mDragAndDropHandler, &DragAndDropHandler::imageDropped, this, &MainWindow::loadImageFromFile);