Reputation: 347
I have a QGraphicsVideoItem added to a QGraphicsView widget. How can I crop the item so I don't see part of the displayed video? I have tried doing this:
class OverlayWidget(QWidget):
def __init__(self):
super().__init__()
scene = QGraphicsScene()
self.video_view = QGraphicsView(self)
self.video_view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.video_view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.video_view.setScene(scene)
player_1 = QMediaPlayer(self)
self.video_item_1 = QGraphicsVideoItem()
player_1.setVideoOutput(self.video_item_1)
scene.addItem(self.video_item_1)
# player_1.setSource("V.mp4")
# player_1.play()
player_2 = QMediaPlayer(self)
self.video_item_2 = QGraphicsVideoItem()
self.video_item_2.setAspectRatioMode(Qt.KeepAspectRatio)
player_2.setVideoOutput(self.video_item_2)
scene.addItem(self.video_item_2)
# player_2.setSource("V_compressed.mp4")
# player_2.play()
self.slider = QSlider(Qt.Horizontal, self)
self.slider.setStyleSheet("""
QSlider::groove:horizontal {
background: transparent;
}
QSlider::handle:horizontal {
background: white;
border: 1px solid black;
border-radius: 3px;
width: 10px;
}
""")
self.slider.valueChanged.connect(self.crop_video)
def resizeEvent(self, event):
super().resizeEvent(event)
self.video_view.resize(self.size())
self.slider.resize(self.size())
self.slider.setRange(0, self.video_view.width())
self.video_item_1.setSize(self.video_view.size())
self.video_item_2.setSize(self.video_view.size())
self.crop_video()
def crop_video(self):
# Crop the video substracting the slider right area
self.video_item_2.setPos(self.slider.value(), 0)
self.video_item_2.setOffset(QPoint(-self.slider.value(), 0))
But the part of the video that has negative X coordinate is still drawn. How can I hide it?
(I don't use QVideoWidget because I need to have the slider over the video, and it seems that the video is always on top of other widgets. I could use QVideoWidget if there is no other choice and put the slider outside the videos)
Upvotes: 2
Views: 232
Reputation: 347
After a lot of trial error and wander through docs, I found that I could override paint
method of a QGraphicsVideo item and set there the QPainter (setClipRect
)
Full code:
from PySide6.QtCore import Qt, QRectF
from PySide6.QtGui import QPainter
from PySide6.QtMultimedia import QMediaPlayer
from PySide6.QtMultimediaWidgets import QGraphicsVideoItem
from PySide6.QtWidgets import (
QWidget,
QApplication,
QMainWindow,
QVBoxLayout,
QLabel,
QSlider,
QSizePolicy,
QGraphicsScene,
QGraphicsView,
QStyleOptionGraphicsItem,
)
class CustomItem(QGraphicsVideoItem):
def __init__(self):
super().__init__()
self.offset = 0
def paint(self, painter: QPainter, option: QStyleOptionGraphicsItem, widget: QWidget):
if self.offset != 0:
painter.setClipRect(QRectF(self.offset, 0, self.size().width(), self.size().height()))
QGraphicsVideoItem.paint(self, painter, option, widget)
class OverlayWidget(QWidget):
def __init__(self):
super().__init__()
scene = QGraphicsScene()
self.video_view = QGraphicsView(self)
self.video_view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.video_view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.video_view.setScene(scene)
player_1 = QMediaPlayer(self)
self.video_item_1 = CustomItem()
player_1.setVideoOutput(self.video_item_1)
scene.addItem(self.video_item_1)
# player_1.setSource("V.mp4") # Set here your video source
player_1.play()
player_2 = QMediaPlayer(self)
self.video_item_2 = CustomItem()
self.video_item_2.setAspectRatioMode(Qt.KeepAspectRatio)
player_2.setVideoOutput(self.video_item_2)
scene.addItem(self.video_item_2)
# player_2.setSource("V_compressed.mp4") # Set here your video source
player_2.play()
self.slider = QSlider(Qt.Horizontal, self)
self.slider.setStyleSheet("""
QSlider::groove:horizontal {
background: transparent;
}
QSlider::handle:horizontal {
background: white;
border: 1px solid black;
border-radius: 3px;
width: 10px;
}
""")
self.slider.valueChanged.connect(self.crop_video)
def resizeEvent(self, event):
super().resizeEvent(event)
self.video_view.resize(self.size())
self.slider.resize(self.size())
self.slider.setRange(0, self.video_view.width())
self.video_item_1.setSize(self.video_view.size())
self.video_item_2.setSize(self.video_view.size())
self.crop_video()
def crop_video(self):
# Crop the video substracting the slider left area
self.video_item_2.offset = self.slider.value()
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.central_widget = QWidget()
self.setCentralWidget(self.central_widget)
self.main_layout = QVBoxLayout()
self.central_widget.setLayout(self.main_layout)
self.label = QLabel("Overlay")
self.label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
self.main_layout.addWidget(self.label)
self.overlay_widget = OverlayWidget()
self.overlay_widget.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
self.main_layout.addWidget(self.overlay_widget)
self.resize(800, 600)
if __name__ == "__main__":
app = QApplication()
window = MainWindow()
window.show()
app.exec()
Upvotes: 1