fristhon
fristhon

Reputation: 91

QVideoWidget not reciving dropEvent (strange behavior)

I want to play a media on dropEvent of a QVideoWidget. I know the playing part, my problem is QVideoWidget not receiving dropEvent like other widgets. I'm wonder this is a bug or I am missing something.

Everything is ok and all three events getting called:

import sys
from PySide6.QtCore import QSize
from PySide6.QtMultimediaWidgets import QVideoWidget
from PySide6.QtWidgets import QApplication, QWidget

class MyWidget(QWidget):
    def __init__(self,*args):
        super().__init__(*args)

        self.setAcceptDrops(True)
        self.setMinimumSize(QSize(600,400))

    def dragEnterEvent(self, event):
        print(event)
        event.accept()

    def dragMoveEvent(self, event):
        print(event)
        event.accept()

    def dropEvent(self, event):
        print(event)

if __name__ == "__main__":
    app = QApplication([])
    widget = MyWidget()
    widget.show()
    sys.exit(app.exec())

But when I use same code with a QVideoWidget , dropEvent not getting called:

import sys
from PySide6.QtCore import QSize
from PySide6.QtMultimediaWidgets import QVideoWidget
from PySide6.QtWidgets import QApplication, QWidget

class MyWidget(QVideoWidget):
    def __init__(self,*args):
        super().__init__(*args)

        self.setAcceptDrops(True)
        self.setMinimumSize(QSize(600,400))

    def dragEnterEvent(self, event):
        print(event)
        event.accept()

    def dragMoveEvent(self, event):
        print(event)
        event.accept()

    def dropEvent(self, event):
        print(event)

if __name__ == "__main__":
    app = QApplication([])
    widget = MyWidget()
    widget.show()
    sys.exit(app.exec())

P.S : I don't know why but in the last code dropEvent works on title bar! I can upload a GIF if needed.

Upvotes: 1

Views: 377

Answers (2)

InikOfDoom
InikOfDoom

Reputation: 11

Thanks, that saved my day! I ran in to same issue and wrote a Qt bug report (haven't found any so far: https://bugreports.qt.io/browse/QTBUG-107668). In C++, this looks like this:

VideoWidget::VideoWidget(QWidget *parent) : QVideoWidget(parent)
{
    QObject *c = findChild<QWidget*>();
    c->installEventFilter(this);
}

bool VideoWidget::eventFilter(QObject *obj, QEvent *ev)
{
    QObject *c = findChild<QWidget*>();

    if(obj == c){
        if(ev->type() == QEvent::DragEnter){
            qDebug()<<"Drag Enter";
            return true;
        }
        else if(ev->type() == QEvent::DragMove){
            //qDebug()<<"Drag Move";
            return true;
        }
        else if(ev->type() == QEvent::Drop){
            qDebug()<<"Drop";
            return true;
        }
    }
    return QVideoWidget::eventFilter(obj, ev);
}

Upvotes: 1

eyllanesc
eyllanesc

Reputation: 243897

You have discovered a bug, QVideoWidget in Qt6 uses a QWindow to speed up painting and this is added as a child of the QVideoWidget so the drag and drop event is not propagated to the parent. A workaround is to use an eventfilter to listen to the event.

import sys

from PySide6.QtCore import QSize, QEvent
from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtMultimediaWidgets import QVideoWidget


class MyWidget(QVideoWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setMinimumSize(QSize(600, 400))
        self.window_child.installEventFilter(self)

    @property
    def window_child(self):
        child = self.findChild(QWidget)
        if child.metaObject().className() == "QWindowContainer":
            return child

    def eventFilter(self, obj, event):
        if obj is self.window_child:
            if event.type() == QEvent.Type.DragEnter:
                print("dragEnterEvent:", event)
            elif event.type() == QEvent.Type.DragMove:
                print("dragMoveEvent:", event)
            elif event.type() == QEvent.Type.Drop:
                print("dropEvent", event)
        return super().eventFilter(obj, event)


if __name__ == "__main__":
    app = QApplication([])
    widget = MyWidget()
    widget.show()
    sys.exit(app.exec())

Upvotes: 3

Related Questions