Skip to content
Advertisement

Creating a non-overlapping QVideoPlayer and PlotWidget in PyQt5

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)
User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement