A fluent design widgets library based on PyQt5 providing modern Windows 11-style UI components
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Media player widgets, video display, and audio/video control components with modern playback interfaces. These components provide comprehensive multimedia functionality with fluent design integration.
Core media player widget with comprehensive playback controls and modern interface design.
class MediaPlayer(QWidget):
def __init__(self, parent=None): ...
def setMedia(self, media: Union[str, QUrl, QMediaContent]): ...
def media(self) -> QMediaContent: ...
def play(self): ...
def pause(self): ...
def stop(self): ...
def setPosition(self, position: int): ...
def position(self) -> int: ...
def setVolume(self, volume: int): ...
def volume(self) -> int: ...
def duration(self) -> int: ...
def state(self) -> QMediaPlayer.State: ...
# Signals
positionChanged = pyqtSignal(int)
durationChanged = pyqtSignal(int)
stateChanged = pyqtSignal(QMediaPlayer.State)
volumeChanged = pyqtSignal(int)
class MediaPlayerBase(QWidget):
def __init__(self, parent=None): ...
def setMediaPlayer(self, player: QMediaPlayer): ...
def mediaPlayer(self) -> QMediaPlayer: ...Usage Example:
from qfluentwidgets import MediaPlayer
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent
from PyQt5.QtCore import QUrl
# Create media player
media_player = MediaPlayer(self)
media_player.setFixedSize(600, 400)
# Load media file
media_file = "path/to/video.mp4"
media_player.setMedia(media_file)
# Connect to signals
media_player.positionChanged.connect(self.on_position_changed)
media_player.durationChanged.connect(self.on_duration_changed)
media_player.stateChanged.connect(self.on_state_changed)
def on_position_changed(self, position):
# Update progress slider
progress_slider.setValue(position)
def on_duration_changed(self, duration):
# Set slider range
progress_slider.setRange(0, duration)
duration_label.setText(self.format_time(duration))
def on_state_changed(self, state):
if state == QMediaPlayer.PlayingState:
play_button.setText("Pause")
else:
play_button.setText("Play")
# Control playback
play_button.clicked.connect(media_player.play)
pause_button.clicked.connect(media_player.pause)
stop_button.clicked.connect(media_player.stop)Dedicated video display widget for rendering video content with proper aspect ratio handling.
class VideoWidget(QVideoWidget):
def __init__(self, parent=None): ...
def setAspectRatioMode(self, mode: Qt.AspectRatioMode): ...
def aspectRatioMode(self) -> Qt.AspectRatioMode: ...
def setFullScreen(self, fullScreen: bool): ...
def isFullScreen(self) -> bool: ...
def sizeHint(self) -> QSize: ...Usage Example:
from qfluentwidgets import VideoWidget, MediaPlayer
from PyQt5.QtCore import Qt
# Create video display
video_widget = VideoWidget(self)
video_widget.setAspectRatioMode(Qt.KeepAspectRatio)
video_widget.setMinimumSize(320, 240)
# Create media player and connect to video widget
player = QMediaPlayer(self)
player.setVideoOutput(video_widget)
# Create media player UI
media_player = MediaPlayer(self)
media_player.setMediaPlayer(player)
# Layout video and controls
layout = QVBoxLayout(self)
layout.addWidget(video_widget, 1) # Video takes most space
layout.addWidget(media_player, 0) # Controls at bottom
# Fullscreen toggle
def toggle_fullscreen():
video_widget.setFullScreen(not video_widget.isFullScreen())
fullscreen_btn.clicked.connect(toggle_fullscreen)
# Handle escape key to exit fullscreen
def keyPressEvent(self, event):
if event.key() == Qt.Key_Escape and video_widget.isFullScreen():
video_widget.setFullScreen(False)
super().keyPressEvent(event)Specialized control bars with playback buttons, progress tracking, and volume controls.
class StandardMediaPlayBar(QWidget):
def __init__(self, parent=None): ...
def setMediaPlayer(self, player: QMediaPlayer): ...
def setPlayButtonVisible(self, visible: bool): ...
def setVolumeButtonVisible(self, visible: bool): ...
def setProgressSliderVisible(self, visible: bool): ...
def setTimeLabelsVisible(self, visible: bool): ...
class SimpleMediaPlayBar(QWidget):
def __init__(self, parent=None): ...
def setMediaPlayer(self, player: QMediaPlayer): ...
def setCompactMode(self, compact: bool): ...
class MediaPlayBarButton(QToolButton):
def __init__(self, parent=None): ...
def __init__(self, icon: Union[FluentIconBase, QIcon, str], parent=None): ...
def setPlayIcon(self, icon: Union[FluentIconBase, QIcon, str]): ...
def setPauseIcon(self, icon: Union[FluentIconBase, QIcon, str]): ...
def setPlaying(self, playing: bool): ...Usage Example:
from qfluentwidgets import (StandardMediaPlayBar, SimpleMediaPlayBar,
MediaPlayBarButton, FluentIcon as FIF)
# Standard media control bar
standard_bar = StandardMediaPlayBar(self)
standard_bar.setMediaPlayer(player)
# Customize visibility
standard_bar.setPlayButtonVisible(True)
standard_bar.setVolumeButtonVisible(True)
standard_bar.setProgressSliderVisible(True)
standard_bar.setTimeLabelsVisible(True)
# Simple media control bar
simple_bar = SimpleMediaPlayBar(self)
simple_bar.setMediaPlayer(player)
simple_bar.setCompactMode(True)
# Custom media buttons
play_pause_btn = MediaPlayBarButton(self)
play_pause_btn.setPlayIcon(FIF.PLAY)
play_pause_btn.setPauseIcon(FIF.PAUSE)
stop_btn = MediaPlayBarButton(FIF.STOP, self)
next_btn = MediaPlayBarButton(FIF.NEXT, self)
prev_btn = MediaPlayBarButton(FIF.PREVIOUS, self)
# Connect custom buttons
play_pause_btn.clicked.connect(self.toggle_playback)
stop_btn.clicked.connect(player.stop)
next_btn.clicked.connect(self.next_track)
prev_btn.clicked.connect(self.previous_track)
def toggle_playback(self):
if player.state() == QMediaPlayer.PlayingState:
player.pause()
play_pause_btn.setPlaying(False)
else:
player.play()
play_pause_btn.setPlaying(True)from qfluentwidgets import *
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent, QMediaPlaylist
from PyQt5.QtCore import QUrl, QTimer
class FluentMediaPlayer(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi()
self.setupMediaPlayer()
self.setupConnections()
def setupUi(self):
# Main layout
layout = QVBoxLayout(self)
# Title bar
title_bar = QHBoxLayout()
self.title_label = TitleLabel("Media Player")
self.minimize_btn = TransparentToolButton(FIF.MINIMIZE)
self.close_btn = TransparentToolButton(FIF.CLOSE)
title_bar.addWidget(self.title_label)
title_bar.addStretch()
title_bar.addWidget(self.minimize_btn)
title_bar.addWidget(self.close_btn)
# Video display area
self.video_widget = VideoWidget(self)
self.video_widget.setAspectRatioMode(Qt.KeepAspectRatio)
self.video_widget.setMinimumSize(640, 360)
# Control panel
control_layout = QHBoxLayout()
# Playback controls
self.prev_btn = MediaPlayBarButton(FIF.PREVIOUS, self)
self.play_pause_btn = MediaPlayBarButton(FIF.PLAY, self)
self.stop_btn = MediaPlayBarButton(FIF.STOP, self)
self.next_btn = MediaPlayBarButton(FIF.NEXT, self)
# Progress controls
self.position_slider = Slider(Qt.Horizontal, self)
self.position_slider.setFixedHeight(20)
# Time labels
self.current_time_label = CaptionLabel("00:00")
self.duration_label = CaptionLabel("00:00")
# Volume controls
self.volume_btn = MediaPlayBarButton(FIF.VOLUME, self)
self.volume_slider = Slider(Qt.Horizontal, self)
self.volume_slider.setRange(0, 100)
self.volume_slider.setValue(70)
self.volume_slider.setFixedWidth(100)
# Add to control layout
control_layout.addWidget(self.prev_btn)
control_layout.addWidget(self.play_pause_btn)
control_layout.addWidget(self.stop_btn)
control_layout.addWidget(self.next_btn)
control_layout.addStretch()
control_layout.addWidget(self.current_time_label)
control_layout.addWidget(self.position_slider, 1)
control_layout.addWidget(self.duration_label)
control_layout.addStretch()
control_layout.addWidget(self.volume_btn)
control_layout.addWidget(self.volume_slider)
# Playlist area
self.playlist_widget = ListWidget(self)
self.playlist_widget.setMaximumHeight(150)
# Add to main layout
layout.addLayout(title_bar)
layout.addWidget(self.video_widget, 1)
layout.addLayout(control_layout)
layout.addWidget(self.playlist_widget)
def setupMediaPlayer(self):
# Media player
self.player = QMediaPlayer(self)
self.player.setVideoOutput(self.video_widget)
# Playlist
self.playlist = QMediaPlaylist(self)
self.player.setPlaylist(self.playlist)
# Position update timer
self.position_timer = QTimer(self)
self.position_timer.timeout.connect(self.update_position)
self.position_timer.start(100) # Update every 100ms
def setupConnections(self):
# Player signals
self.player.stateChanged.connect(self.on_state_changed)
self.player.positionChanged.connect(self.on_position_changed)
self.player.durationChanged.connect(self.on_duration_changed)
self.player.volumeChanged.connect(self.on_volume_changed)
# Control connections
self.play_pause_btn.clicked.connect(self.toggle_playback)
self.stop_btn.clicked.connect(self.player.stop)
self.prev_btn.clicked.connect(self.playlist.previous)
self.next_btn.clicked.connect(self.playlist.next)
# Slider connections
self.position_slider.sliderPressed.connect(self.on_position_slider_pressed)
self.position_slider.sliderReleased.connect(self.on_position_slider_released)
self.volume_slider.valueChanged.connect(self.player.setVolume)
# Playlist connections
self.playlist_widget.itemDoubleClicked.connect(self.play_selected_item)
def add_media_file(self, file_path: str):
"""Add media file to playlist"""
media_content = QMediaContent(QUrl.fromLocalFile(file_path))
self.playlist.addMedia(media_content)
# Add to playlist widget
file_name = os.path.basename(file_path)
self.playlist_widget.addItem(file_name)
def toggle_playback(self):
"""Toggle between play and pause"""
if self.player.state() == QMediaPlayer.PlayingState:
self.player.pause()
else:
self.player.play()
def on_state_changed(self, state):
"""Handle player state changes"""
if state == QMediaPlayer.PlayingState:
self.play_pause_btn.setIcon(FIF.PAUSE.icon())
else:
self.play_pause_btn.setIcon(FIF.PLAY.icon())
def on_position_changed(self, position):
"""Handle position changes"""
if not self.position_slider.isSliderDown():
self.position_slider.setValue(position)
self.current_time_label.setText(self.format_time(position))
def on_duration_changed(self, duration):
"""Handle duration changes"""
self.position_slider.setRange(0, duration)
self.duration_label.setText(self.format_time(duration))
def on_volume_changed(self, volume):
"""Handle volume changes"""
self.volume_slider.setValue(volume)
# Update volume icon
if volume == 0:
self.volume_btn.setIcon(FIF.MUTE.icon())
elif volume < 50:
self.volume_btn.setIcon(FIF.VOLUME.icon())
else:
self.volume_btn.setIcon(FIF.VOLUME.icon())
def on_position_slider_pressed(self):
"""Handle position slider press"""
self.position_timer.stop()
def on_position_slider_released(self):
"""Handle position slider release"""
self.player.setPosition(self.position_slider.value())
self.position_timer.start()
def play_selected_item(self, item):
"""Play selected playlist item"""
row = self.playlist_widget.row(item)
self.playlist.setCurrentIndex(row)
self.player.play()
def format_time(self, milliseconds):
"""Format time in MM:SS format"""
seconds = milliseconds // 1000
minutes = seconds // 60
seconds = seconds % 60
return f"{minutes:02d}:{seconds:02d}"
def update_position(self):
"""Update position display"""
if self.player.state() == QMediaPlayer.PlayingState:
position = self.player.position()
if not self.position_slider.isSliderDown():
self.position_slider.setValue(position)
# Usage
media_player = FluentMediaPlayer()
media_player.add_media_file("video1.mp4")
media_player.add_media_file("audio1.mp3")
media_player.show()class CustomMediaControls(QWidget):
def __init__(self, player: QMediaPlayer, parent=None):
super().__init__(parent)
self.player = player
self.setupUi()
def setupUi(self):
layout = QHBoxLayout(self)
# Playback speed control
speed_combo = ComboBox(self)
speed_combo.addItems(["0.5x", "0.75x", "1.0x", "1.25x", "1.5x", "2.0x"])
speed_combo.setCurrentText("1.0x")
speed_combo.currentTextChanged.connect(self.change_playback_speed)
# Quality selection
quality_combo = ComboBox(self)
quality_combo.addItems(["Auto", "1080p", "720p", "480p", "360p"])
# Fullscreen button
fullscreen_btn = ToolButton(FIF.FULL_SCREEN, self)
fullscreen_btn.clicked.connect(self.toggle_fullscreen)
layout.addWidget(QLabel("Speed:"))
layout.addWidget(speed_combo)
layout.addWidget(QLabel("Quality:"))
layout.addWidget(quality_combo)
layout.addStretch()
layout.addWidget(fullscreen_btn)
def change_playback_speed(self, speed_text):
speed = float(speed_text.replace('x', ''))
self.player.setPlaybackRate(speed)class PlaylistManager:
def __init__(self, playlist: QMediaPlaylist, list_widget: ListWidget):
self.playlist = playlist
self.list_widget = list_widget
self.media_files = []
def add_files(self, file_paths: List[str]):
for file_path in file_paths:
self.add_file(file_path)
def add_file(self, file_path: str):
media = QMediaContent(QUrl.fromLocalFile(file_path))
self.playlist.addMedia(media)
self.media_files.append(file_path)
# Add to UI
file_name = os.path.basename(file_path)
self.list_widget.addItem(file_name)
def remove_current(self):
current_index = self.playlist.currentIndex()
if current_index >= 0:
self.playlist.removeMedia(current_index)
self.media_files.pop(current_index)
self.list_widget.takeItem(current_index)
def shuffle(self):
self.playlist.shuffle()
def set_repeat_mode(self, mode: QMediaPlaylist.PlaybackMode):
self.playlist.setPlaybackMode(mode)def handle_media_errors(self):
"""Handle media player errors"""
self.player.error.connect(self.on_media_error)
def on_media_error(self, error):
"""Handle media playback errors"""
error_messages = {
QMediaPlayer.NoError: "No error",
QMediaPlayer.ResourceError: "Resource error - file not found or corrupted",
QMediaPlayer.FormatError: "Format error - unsupported media format",
QMediaPlayer.NetworkError: "Network error - connection failed",
QMediaPlayer.AccessDeniedError: "Access denied - insufficient permissions",
QMediaPlayer.ServiceMissingError: "Service missing - codec not available"
}
message = error_messages.get(error, f"Unknown error: {error}")
# Show error dialog
error_dialog = MessageBox("Media Error", message, self)
error_dialog.exec()Install with Tessl CLI
npx tessl i tessl/pypi-pyqt-fluent-widgets