![](/img/trans.png)
[英]How to consume QEvent::WindowBlocked so that specific window is always active?
[英]How to discard an QEvent instead of just ignoring it
我有两个小部件ParentWidget
和ChildWidget
都是从QWidget
派生出来的,都覆盖了void dragEnterEvent(QDragEnterEvent *event)
。
现在ChildWidget
包含在ParentWidget
。 现在假设某个QDragEvent*
被调用的event
可能对ParentWidget
有效,但对于ChildWidget
没有,并且假设调用了对于ChildWidget
dragEnterEvent
。
现在我可以调用event->ignore()
来忽略ChildWidget
的事件,但是调用了ParentWidget
dragEnterEvent
。
这是我的问题。 我不想,那dragEnterEvent
为ParentWidget
获取调用,如果该事件是在已经废弃ChildWidget
。
简单来说,我只是不希望事件被忽略,而且事件需要在ChildWidget
的dragEnterEvent
中完全丢弃。
如何在ParentWidget
和ChildWidget
是松耦合组件的假设下实现这样的行为?
最小的例子
以下示例显示了我正在尝试实现的内容,并且在某种意义上也是一种可行的方法。 在更复杂的情况下,它将导致过于复杂的代码。
ChildWidget
接受以txt
结尾的文件名的删除,而ParentWidget
接受所有的drop,除了ChildWidget
已经忽略的ChildWidget
。
main.cpp中
#include <QApplication>
#include "ParentWidget.h"
int main(int argc, char** args) {
QApplication app(argc, args);
auto widget=new ParentWidget;
widget->show();
app.exec();
}
ParentWidget.h
#pragma once
#include <QWidget>
#include <QDebug>
#include <QDragEnterEvent>
#include <QHBoxLayout>
#include <QLabel>
#include "ChildWidget.h"
class ParentWidget : public QWidget {
Q_OBJECT
public:
ParentWidget(QWidget* parent = nullptr) : QWidget(parent) {
setLayout(new QHBoxLayout);
setAcceptDrops(true);
layout()->addWidget(new QLabel("ParentLabel"));
layout()->addWidget(new ChildWidget);
}
void dragEnterEvent(QDragEnterEvent *event) override {
qDebug() << "Parent";
// Check if event was already ignored in ChildWidget?
if (auto childWidget = qobject_cast<ChildWidget*>(childAt(event->pos()))) {
event->ignore();
}
else {
event->acceptProposedAction();
}
}
};
ChildWidget.h
#pragma once
#include <QWidget>
#include <QUrl>
#include <QMimeData>
#include <QDragEnterEvent>
#include <QLabel>
#include <QDebug>
#include <QByteArray>
#include <QHBoxLayout>
class ChildWidget : public QWidget {
Q_OBJECT
public:
ChildWidget(QWidget* parent = nullptr) : QWidget(parent) {
setAcceptDrops(true);
setLayout(new QHBoxLayout);
layout()->addWidget(new QLabel("ChildLabel"));
}
void dragEnterEvent(QDragEnterEvent *event) override {
qDebug() << "Child";
if (auto mimeData=event->mimeData()) {
auto url = QUrl(mimeData->text());
if (!url.isValid()) { event->ignore(); return; }
if (!url.isLocalFile()) { event->ignore(); return; }
auto filename = url.fileName();
if (!filename.endsWith(".txt")) { event->ignore(); return; }
// ChildWidget can only process txt files.
qDebug() << url.fileName();
event->acceptProposedAction();
}
else {
event->ignore();
}
}
};
如果您希望丢弃该事件,则需要接受它:
void dragEnterEvent(QDragEnterEvent *event) override {
qDebug() << "Child";
if (auto mimeData=event->mimeData()) {
[...]
event->acceptProposedAction();
}
else {
event->setAction(Qt::IgnoreAction);
event->accept();
}
}
这就是Qt将事件分派给小部件的方式:事件从子节点传播到父节点,直到小部件接受它为止。
从Qt代码:
while (w) {
if (w->isEnabled() && w->acceptDrops()) {
res = d->notify_helper(w, dragEvent); // calls dragEnterEvent() on w
if (res && dragEvent->isAccepted()) {
QDragManager::self()->setCurrentTarget(w);
break; // The event was accepted, we break, the event will not propagate to the parent
}
}
if (w->isWindow())
break;
dragEvent->p = w->mapToParent(dragEvent->p.toPoint());
w = w->parentWidget();
}
您的解决方案是一个不错的解决方案
或者,您可以将事件类型更改为非拖动事件。 由于事件不再是QDragEnterEvent
,因此不会将其分派给父级。 有两种方法可以实现它:一种是更改QEvent
的t
(类型)成员。 另一个是就地破坏事件并在那里重新创建一个普通的null事件。
// https://github.com/KubaO/stackoverflown/tree/master/questions/event-discard-43885834
#include <QtWidgets>
void wipeEvent(QEvent * event) {
struct Helper : QEvent {
static void wipe(QEvent * e) {
static_cast<Helper*>(e)->t = QEvent::None;
}
};
Helper::wipe(event);
}
void wipeEvent2(QEvent *event) {
event->~QEvent(); // OK since the destructor is virtual.
new (event) QEvent(QEvent::None);
}
class ChildWidget : public QWidget {
Q_OBJECT
QHBoxLayout m_layout{this};
QLabel m_label{"ChildLabel"};
public:
ChildWidget() {
setAcceptDrops(true);
m_layout.addWidget(&m_label);
}
void dragEnterEvent(QDragEnterEvent *event) override {
qDebug() << "Child";
while (auto mimeData=event->mimeData()) {
auto url = QUrl(mimeData->text());
if (!url.isValid()) break;
if (!url.isLocalFile()) break;
auto filename = url.fileName();
if (!filename.endsWith(".txt")) break;
// ChildWidget can only process txt files.
qDebug() << url.fileName();
return event->acceptProposedAction();
}
wipeEvent(event);
}
};
class ParentWidget : public QWidget {
Q_OBJECT
QHBoxLayout m_layout{this};
QLabel m_label{"ParentLabel"};
ChildWidget m_child;
public:
ParentWidget() {
setAcceptDrops(true);
m_layout.addWidget(&m_label);
m_layout.addWidget(&m_child);
}
void dragEnterEvent(QDragEnterEvent *event) override {
qDebug() << "Parent";
event->acceptProposedAction();
}
};
int main(int argc, char** args) {
QApplication app{argc, args};
ParentWidget widget;
widget.show();
app.exec();
}
#include "main.moc"
经过长时间的聊天,我找到了以下更好的解决方案来解决我的问题。 解决方案与Benjamin T.的解决方案类似。再次感谢ThibautB。 为了富有成效的讨论。
这是我的工作代码。
main.cpp中
#include <QApplication>
#include "ParentWidget.h"
int main(int argc, char** args) {
QApplication app(argc, args);
auto widget=new ParentWidget;
widget->show();
app.exec();
}
ChildWidget.h
#pragma once
#include <QWidget>
#include <QUrl>
#include <QMimeData>
#include <QDragEnterEvent>
#include <QLabel>
#include <QDebug>
#include <QByteArray>
#include <QHBoxLayout>
//#include "MyDragEnterEvent.h"
class ChildWidget : public QWidget {
Q_OBJECT
public:
ChildWidget(QWidget* parent = nullptr) : QWidget(parent) {
setAcceptDrops(true);
setLayout(new QHBoxLayout);
layout()->addWidget(new QLabel("ChildLabel"));
}
void dragEnterEvent(QDragEnterEvent *event) {
qDebug() << "Child";
if (auto mimeData=event->mimeData()) {
auto url = QUrl(mimeData->text());
if (!url.isValid()) { event->setDropAction(Qt::DropAction::IgnoreAction); event->ignore(); return; }
if (!url.isLocalFile()) { event->setDropAction(Qt::DropAction::IgnoreAction); event->ignore(); return; }
auto filename = url.fileName();
if (!filename.endsWith(".txt")) { event->setDropAction(Qt::DropAction::IgnoreAction); event->ignore(); return; }
// ChildWidget can only process txt files.
qDebug() << url.fileName();
event->acceptProposedAction();
}
else {
qDebug() << "Ignored in Child";
event->setDropAction(Qt::DropAction::IgnoreAction);
event->ignore();
}
}
};
ParentWidget.h
#pragma once
#include <QWidget>
#include <QDebug>
#include <QDragEnterEvent>
#include <QHBoxLayout>
#include <QLabel>
#include "ChildWidget.h"
class ParentWidget : public QWidget {
Q_OBJECT
public:
ParentWidget(QWidget* parent = nullptr) : QWidget(parent) {
setLayout(new QHBoxLayout);
setAcceptDrops(true);
layout()->addWidget(new QLabel("ParentLabel"));
layout()->addWidget(new ChildWidget);
}
void dragEnterEvent(QDragEnterEvent *event) override {
if (event->dropAction() == Qt::IgnoreAction) {
qDebug() << "Ignored in Parent";
event->ignore();
}
else {
qDebug() << "Accepted in Parent";
event->acceptProposedAction();
}
}
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.