2017-05-10 23 views
1

두 개의 위젯 ParentWidgetChildWidget은 모두 QWidget에서 파생되었으며 둘 다 void dragEnterEvent(QDragEnterEvent *event)을 재정의했습니다.QEvent를 그냥 무시하는 대신 폐기하는 방법

ChildWidgetParentWidget에 포함되어 있습니다. 이제 QDragEvent*이라는 eventParentWidget에는 유효하지만 ChildWidget에는 유효하지 않으며 ChildWidget에 대한 dragEnterEvent이 있다고 가정합니다.

이제 ChildWidget에 대한 이벤트를 무시하기 위해 event->ignore()을 호출 할 수 있지만 ParentWidget에 대한 dragEnterEvent을 호출 할 수 있습니다.

그리고 내 문제입니다. 그 이벤트가 이미 ChildWidget에서 삭제 된 경우 ParentWidget에 대한 dragEnterEvent이 호출되기를 원하지 않습니다.

간단히 말해서 나는 단지 이벤트가 무시되기를 원하지 않지만 더 나아가 이벤트는 dragEnterEventChildWidget 안에 완전히 버려야합니다.

ParentWidgetChildWidget이 느슨하게 결합 된 구성 요소라는 가정하에 어떻게 이러한 동작을 수행 할 수 있습니까?

최소한의 예

다음 예는 나는 또한 달성하기 위해 노력하고있어 보여줍니다 어떤 의미에서 가능한 방법입니다. 보다 복잡한 시나리오의 경우 지나치게 복잡한 코드가 발생합니다. ParentWidget 이미 ChildWidget 무시 제외한 모든 방울을 받아들이는 반면

ChildWidgettxt 끝나는 파일 이름을 드롭을 받아들입니다.

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(); 
     } 
    } 
}; 
+0

당신은 당신의 구현을 보여줄 수 있습니까? 가상의 –

+0

@ThibautB이기 때문에''''ChildWidget'''에 대해'''dragEnterEvent'''를 재 구현할 수 있습니다. 두 위젯 인'ChildWidget'과'ParentWidget'에 대해'dragEnterEvent'를 구현했습니다. 'ParentWidget'에 대한'dragEnterEvent'는 이벤트가'ChildWidget'의'dragEnterEvent'에서 무시되면 다르게 행동해야한다는 것입니다. – Aleph0

+0

@ ThibautB. 'QDragEnterEvent'가이 부울을 전송할 수 있습니까? – Aleph0

답변

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(); 
} 
+0

이 멋진 솔루션에 많은 감사를드립니다. 어제도 비슷한 솔루션을 발견했습니다. 나는 그것을 여기에 게시 할 것이다. – Aleph0

0

귀하의 솔루션 괜찮은 해결 방법입니다.

또는 이벤트 유형을 드래그가 아닌 이벤트로 변경할 수 있습니다. 이벤트가 QDragEnterEvent이 아니므로 부모에게 전달되지 않습니다. 이를 구현하는 방법은 두 가지가 있습니다. 하나는 t (유형) 구성원을 QEvent으로 변경하는 것입니다. 또 다른 방법은 이벤트를 내부에서 삭제하고 일반 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" 
0

긴 채팅 어제 후에 나는 내 문제에 대한 다음과 같은 더 나은 솔루션을 발견했다. 해결책은 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(); 
     } 
    } 
};