我有两个小部件ParentWidget
和ChildWidget
都来自QWidget
并且都覆盖void dragEnterEvent(QDragEnterEvent *event)
。
现在ChildWidget
包含ParentWidget
。现在假设某个名为QDragEvent*
的{{1}}可能对event
有效,但对ParentWidget
无效,并假设ChildWidget
的{{1}}被调用。
现在我可以调用dragEnterEvent
来忽略ChildWidget
的事件,但调用event->ignore()
的{{1}}。
这是我的问题。如果事件已在ChildWidget
中丢弃,我不想要dragEnterEvent
ParentWidget
被调用。
简单地说,我只是不想忽略该事件,而且事件需要在dragEnterEvent
ParentWidget
内完全丢弃。
如果假设ChildWidget
和dragEnterEvent
是松散耦合的组件,怎么能实现这样的行为呢?
最小示例
以下示例显示了我想要实现的目标,并且在某种意义上也是一种可行的方法。如果出现更复杂的情况,则会导致代码过于复杂。
ChildWidget
接受以ParentWidget
结尾的文件名,而ChildWidget
接受所有丢弃,但ChildWidget
已忽略的除外。
的main.cpp
txt
ParentWidget.h
ParentWidget
ChildWidget.h
ChildWidget
答案 0 :(得分:3)
如果您希望丢弃该事件,则需要接受:
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();
}
答案 1 :(得分:0)
您的解决方案是一个不错的解决方法。
或者,您可以将事件类型更改为非拖动事件。由于事件不再是t
,因此不会将其分派给父母。有两种方法可以实现它:一种是更改QEvent
的{{1}}(类型)成员。另一个是就地破坏事件并在那里重新创建一个普通的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"