Unsolved 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 thenQVideoWidget.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
returnsclicked.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.
-
Hi and welcome to devnet,
Do you have the same issue with PySide (2 and/or 6) ?