Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QListWidget - unexpected behavior after QVideoWidget leaves fullscreen



  • I'm building a media player that has a QListWidget to select media for playback. But I'm finding that after I set QVideoWidget.setFullScreen(True) and then QVideoWidget.setFullScreen(False), the QListWidget doesn't behave as it did before toggling fullscreen.

    • Mouse hover doesn't register on the ListWidget after exiting fullscreen
    • It also doesn't seem to register if you hover onto the ListWidget from the media playback area - if you approach from the media viewport, it doesn't work. But if you approach from the control bar beneath the player, it works. This behavior occurs even prior to going fullscreen.
    • Clicking around on the screen will sometimes restore functionality, but not always
    • If you click on the ListWidget when the issue is occurring, mousePressEvent returns clicked.objectName() = 'qt_scrollarea_viewport' - normally the mousePressEvent doesn't occur when I click on the ListWidget (prior to fullscreen) as the widget has its own mouse press slot.
    • Sometimes (not sure how to consistently recreate this) the ListWidget is hidden behind the video player after exiting full screen.
    • Sometimes when exiting fullscreen, the video player detaches from the main window.
    • I added another ListWidget at the bottom just to rule out any oddities with the popup behavior.
    • I added a delay on the fullscreen button because if it happens instantly, the fullscreen button maintains focus/keeps the hover animation. I thought it might have something to do with that, but the delay hasn't fixed the List behavior.
    • I'm on macOS 11.4 (Intel), PyQt5==5.15.4

    Edit: I added self.chapter_list_popup.itemClicked.connect(lambda: print('Item clicked')) - and when the issue is occurring, the clicks don't even register. So the ListWidget is basically unusable after leaving fullscreen.

    Minimum reproducible example:

    
    
    import sys
    
    from PyQt5.QtCore import *
    from PyQt5.QtMultimediaWidgets import QVideoWidget
    from PyQt5.QtWidgets import *
    from PyQt5.QtMultimedia import QMediaContent, QMediaPlayer
    
    
    class Video_Widget(QVideoWidget):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
    
        def keyPressEvent(self, event):
            if event.key() == Qt.Key_Escape and self.isFullScreen():
                self.setFullScreen(False)
                event.accept()
    
        def mouseDoubleClickEvent(self, event):
            if self.isFullScreen():
                self.setFullScreen(False)
                event.accept()
    
    class Ui_MainWindow(object):
    
        def setupUi(self, MainWindow):
            MainWindow.resize(1514, 593)
            self.central_widget = QWidget(MainWindow)
            self.grid_layout = QGridLayout(self.central_widget)
            self.top_hbar_layout = QHBoxLayout()
            self.grid_layout.addLayout(self.top_hbar_layout, 0, 0, 1, 1)
            self.video_widget = Video_Widget(self.central_widget)
            self.video_widget.setAspectRatioMode(Qt.KeepAspectRatio)
            self.media_player = QMediaPlayer(self.central_widget, QMediaPlayer.VideoSurface)
            self.media_player.setVideoOutput(self.video_widget)
            self.video_widget.setMinimumSize(QSize(0, 500))
            self.grid_layout.addWidget(self.video_widget, 1, 0, 1, 1)
    
            self.control_bar_main_layout = QHBoxLayout()
            self.control_bar_main_layout.setSizeConstraint(QLayout.SetDefaultConstraint)
            self.control_bar_left_layout = QHBoxLayout()
            self.control_bar_left_spacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
            self.control_bar_left_layout.addItem(self.control_bar_left_spacer)
            self.chapter_select_button = QPushButton(self.central_widget)
            self.chapter_select_button.clicked.connect(self.toggle_chapter_list)
            self.control_bar_left_layout.addWidget(self.chapter_select_button)
            self.chapter_list_popup = QListWidget(self.central_widget)
            self.chapter_list_popup.setAlternatingRowColors(True)
            self.chapter_list_popup.addItems(['Chapter 1', 'Chapter 2', 'Chapter 3'])
            setattr(self.chapter_list_popup, 'toggled_on', False)
            self.chapter_list_popup.setGeometry(0, 0, 0, 0)
            self.chapter_list_popup.clicked.connect(self.toggle_chapter_list)
            self.control_bar_main_layout.addLayout(self.control_bar_left_layout)
            self.control_bar_center_layout = QHBoxLayout()
            self.play_button = QPushButton(self.central_widget)
            self.play_button.setMaximumSize(QSize(45, 16777215))
            self.play_button.setEnabled(True)
            self.play_button.setEnabled(True)
            self.control_bar_center_layout.addWidget(self.play_button)
            self.control_bar_main_layout.addLayout(self.control_bar_center_layout)
            self.control_bar_right_layout = QHBoxLayout()
            self.fullscreen_button = QPushButton(self.central_widget)
            self.fullscreen_button.setMaximumSize(QSize(150, 16777215))
            self.control_bar_right_layout.addWidget(self.fullscreen_button)
            self.right_spacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
            self.control_bar_right_layout.addItem(self.right_spacer)
            self.control_bar_main_layout.addLayout(self.control_bar_right_layout)
            self.control_bar_main_layout.setStretch(0, 5)
            self.control_bar_main_layout.setStretch(1, 1)
            self.control_bar_main_layout.setStretch(2, 5)
            self.grid_layout.addLayout(self.control_bar_main_layout, 2, 0, 1, 1)
            self.grid_layout.setRowStretch(0, 1)
            self.grid_layout.setRowStretch(1, 20)
            self.grid_layout.setRowStretch(2, 1)
    
            self.testing_layout = QHBoxLayout()
            self.testing_layout.setGeometry(QRect(0, 0, 600, 200))
            self.testing_list = QListWidget()
            self.testing_list.addItems(['1', '2', '3', '4'])
            self.testing_layout.addWidget(self.testing_list)
            self.grid_layout.addLayout(self.testing_layout, 3, 0, 2, 1)
    
            MainWindow.setCentralWidget(self.central_widget)
    
    
    
            # BIND FUNCTIONS
            self.play_button.clicked.connect(self.play)
            self.media_player.stateChanged.connect(self.media_state_changed)
            self.fullscreen_button.pressed.connect(self.fullscreen)
            self.retranslateUi(MainWindow)
            QMetaObject.connectSlotsByName(MainWindow)
    
        def retranslateUi(self, MainWindow):
            _translate = QCoreApplication.translate
            MainWindow.setWindowTitle(_translate('MainWindow', 'MainWindow'))
    
    
            self.play_button.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
            self.fullscreen_button.setText('FULL SCREEN')
            self.chapter_select_button.setText('CHAPTER SELECT')
            self.central_widget.setStyleSheet('QListView::item:hover {background: red;}')
    
    
    class MainWindow(QMainWindow, Ui_MainWindow):
    
        def __init__(self, *args, **kwargs):
            super(MainWindow, self).__init__(*args, **kwargs)
    
            self.setupUi(self)
    
    
    
    
    
        def exit_call(self):
            sys.exit(app.exec_())
    
        def fullscreen(self):
            timer = QTimer()
            timer.singleShot(2000, lambda: self.video_widget.setFullScreen(True))
    
        def media_state_changed(self, state):
            if self.media_player.state() == QMediaPlayer.PlayingState:
                self.play_button.setIcon(
                    self.style().standardIcon(QStyle.SP_MediaPause))
            else:
                self.play_button.setIcon(
                    self.style().standardIcon(QStyle.SP_MediaPlay))
    
        def mousePressEvent(self, event):
            clicked = self.childAt(event.localPos().toPoint())
            print(f'{clicked.objectName() = }')
    
    
        def open_file(self, url=None):
    
            if url:
                self.media_player.setMedia(QMediaContent(
                    QUrl(url)))
    
    
        def play(self):
            if self.media_player.state() == QMediaPlayer.PlayingState:
                self.media_player.pause()
            else:
                self.media_player.play()
    
    
    
        def toggle_chapter_list(self):
    
            chapters = self.chapter_list_popup
            chapters.show()
            chapters.activateWindow()
            chapters.raise_()
            item_height = chapters.sizeHintForRow(0)
            visible_height = item_height * chapters.model().rowCount() + 3
            visible_y = self.video_widget.y() + self.video_widget.height() - visible_height
            hidden_y = self.video_widget.y() + self.video_widget.height()
    
            if not chapters.toggled_on:
                target_height = visible_height
                target_y = visible_y
                source_y = hidden_y
            else:
                target_height = 0
                target_y = hidden_y
                source_y = visible_y
    
            chapters.toggled_on = not chapters.toggled_on
    
            chapters.animation = QPropertyAnimation(chapters, b'geometry')
            chapters.animation.setDuration(750)
            chapters.animation.setEasingCurve(QEasingCurve.InOutCubic)
            chapters.animation.setStartValue(QRect(
                self.chapter_select_button.x(),
                source_y,
                chapters.sizeHintForColumn(0) + 5,
                # self.chapter_select_button.width(),
                chapters.height()
            ))
            chapters.animation.setEndValue(QRect(
                self.chapter_select_button.x(),
                target_y,
                chapters.sizeHintForColumn(0) + 5,
                # self.chapter_select_button.width(),
                target_height
            )
            )
    
            chapters.animation.start()
    
    if __name__ == "__main__":
    
        app = QApplication(sys.argv)
        window = MainWindow()
        window.show()
        window.open_file(url="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4")
        sys.exit(app.exec_())
    
    
    
    
    


  • I've found a solution for the ListWidget being hidden behind the VideoWidget - I simply recreate the ListWidget on the fullscreenChanged signal.

    However, the hover effect is still gone - I'm going to try and test this out on Windows today to see if it's a macOS specific problem, as I've yet to find any examples (through copious amounts of googling) where this has happened to someone else.



  • Confirmed, I don't seem to have this problem on Windows - so it might be a macOS specific bug.


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    Do you have the same issue with PySide (2 and/or 6) ?


Log in to reply