I am trying to create an app in PyQt5 that has a media (video) player, a graph, and a few buttons. Currently, whenever I try to add the video and graph widgets, they compete for space (lay on top of one another), even when using QGridLayout.
Here is the entire file so far. The important parts are under ‘Create video object’, ‘Create plot’, and ‘Create GUI Layout’.
Any suggestions for getting the video player to occupy the top portion of the window and the graph to occupy a region underneath?
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QGridLayout, QFileDialog, QVBoxLayout, QHBoxLayout from pyqtgraph import PlotWidget from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent from PyQt5.QtMultimediaWidgets import QVideoWidget from PyQt5.QtCore import QUrl import sys class MainWindow(QWidget): def __init__(self): super().__init__() self.setGeometry(300, 100, 900, 600) self.init_gui() self.show() def init_gui(self): # Create media object self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) # Create video object self.videoWidget = QVideoWidget() # Create plot (can't get to size properly) self.plotWidget = PlotWidget() # Create 'Video' button self.videoBtn = QPushButton('Open Video') self.videoBtn.clicked.connect(self.open_video) # Create 'Event Index' Button self.eventIndexBtn = QPushButton('Event Index') self.eventIndexBtn.setEnabled(False) self.eventIndexBtn.clicked.connect(self.open_event_times) # Create 'Time Series' Button self.timeSeriesBtn = QPushButton('Time Series') self.timeSeriesBtn.setEnabled(False) self.timeSeriesBtn.clicked.connect(self.open_time_series) # Create 'Prev' Button self.prevBtn = QPushButton('Prev') self.prevBtn.setEnabled(False) # Create 'Next' Button self.nextBtn = QPushButton('Next') self.nextBtn.setEnabled(False) # Create 'Replay' Button self.replayBtn = QPushButton('Replay') self.replayBtn.setEnabled(False) # Create file dialog layout fileBoxLayout = QVBoxLayout() fileBoxLayout.addWidget(self.videoBtn) fileBoxLayout.addWidget(self.eventIndexBtn) fileBoxLayout.addWidget(self.timeSeriesBtn) # Create controls layout controlBoxLayout = QHBoxLayout() controlBoxLayout.addWidget(self.prevBtn) controlBoxLayout.addWidget(self.nextBtn) controlBoxLayout.addWidget(self.replayBtn) # Create GUI layout GUILayout = QGridLayout() GUILayout.addWidget(self.videoWidget, 0, 0, 8, 9) GUILayout.addWidget(self.plotWidget, 8, 0, 2, 9) GUILayout.addLayout(fileBoxLayout, 10, 0, 2, 3) GUILayout.addLayout(controlBoxLayout, 10, 3, 2, 6) self.setLayout(GUILayout) self.mediaPlayer.setVideoOutput(self.videoWidget) def open_video(self): video_dialog = QFileDialog(self) video_dialog.setNameFilters(["Videos (*.mp4 *.avi *.mov *.flv *.wmv)"]) video_dialog.selectNameFilter("Videos (*.mp4 *.avi *.mov *.flv *.wmv)") video_dialog.exec_() video_file_name = video_dialog.selectedFiles() if len(video_file_name) != 0: self.eventIndexBtn.setEnabled(True) # Load first frame self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(video_file_name[0]))) self.mediaPlayer.setPosition(0) self.mediaPlayer.play() self.mediaPlayer.pause() def open_event_times(self): event_times_dialog = QFileDialog(self) event_times_dialog.setNameFilters(["Text (*.csv)"]) event_times_dialog.selectNameFilter("Text (*.csv)") event_times_dialog.exec_() event_times_file_name = event_times_dialog.selectedFiles() if len(event_times_file_name) != 0: self.timeSeriesBtn.setEnabled(True) self.nextBtn.setEnabled(True) def open_time_series(self): time_series_dialog = QFileDialog(self) time_series_dialog.setNameFilters(["Text (*.csv)"]) time_series_dialog.selectNameFilter("Text (*.csv)") time_series_dialog.exec_() time_series_file_name = time_series_dialog.selectedFiles() if __name__ == '__main__': app = QApplication(sys.argv) window = MainWindow() sys.exit(app.exec_())
Advertisement
Answer
The problem is that the QVideoWidget at startup does not have to display anything so the sizeHint is (-1x-1) making it occupy the smallest possible size causing the problem you are seeing.
A possible solution is to establish the same stretching factor between rows 0 and 1, it is not necessary nor should you place the proportions in the span, considering the above the solution is:
# Create GUI layout GUILayout = QGridLayout() GUILayout.addWidget(self.videoWidget, 0, 0, 1, 9) GUILayout.addWidget(self.plotWidget, 1, 0, 1, 9) GUILayout.addLayout(fileBoxLayout, 2, 0, 2, 3) GUILayout.addLayout(controlBoxLayout, 3, 3, 2, 6) GUILayout.setRowStretch(0, 1) GUILayout.setRowStretch(1, 1)