Files
MediaCast4/ui/ui_window.py
2026-01-15 15:56:37 +08:00

406 lines
13 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import socket
import sys
import ui.resources
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel, QGroupBox, QFrame, QPushButton, \
QListWidget, QSlider, QApplication, QComboBox
class IconManager:
"""图标管理器处理Qt资源系统的图标加载"""
@staticmethod
def get_icon(icon_name="icon"):
"""
从Qt资源系统加载图标
支持格式优先级:
1. 根据平台自动选择格式
2. 使用资源别名
3. 使用完整路径
"""
# 根据平台选择图标格式
platform = sys.platform
if platform == "win32":
extensions = [".ico", ".png"]
elif platform == "darwin": # macOS
extensions = [".icns", ".png"]
else: # Linux和其他
extensions = [".png", ".svg"]
# 尝试不同的路径格式
icon = QIcon()
for ext in extensions:
resource_path = f":/icons/{icon_name}{ext}"
icon = QIcon(resource_path)
if not icon.isNull():
print(f"✓ 从资源加载: {resource_path}")
return icon
# 如果都没找到,创建空图标
if icon.isNull():
print("⚠ 无法从资源加载图标,使用默认图标")
# 可以使用Qt内置图标作为备选
icon = QIcon.fromTheme("application-x-executable")
return icon
class UiWindow:
"""
ui窗口设计
"""
def init_ui(self):
"""初始化UI界面"""
version = "v1.2.1"
app_name = "多媒体投屏 by yqsphp"
self.setWindowTitle(app_name)
self.setGeometry(100, 100, 700, 500)
# 1. 加载主图标
icon = IconManager.get_icon()
# 2. 设置窗口图标(标题栏)
self.setWindowIcon(icon)
# 3. 设置应用程序图标(任务栏)
QApplication.instance().setWindowIcon(icon)
# Windows专用设置AppUserModelID非常重要
if sys.platform == "win32":
try:
from ctypes import windll
# 唯一ID格式公司名.程序名.版本
myappid = app_name + " " + version
windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
except ImportError:
pass
# 创建中央部件
central_widget = QWidget()
self.setCentralWidget(central_widget)
# 主布局
main_layout = QVBoxLayout(central_widget)
main_layout.setSpacing(10)
main_layout.setContentsMargins(10, 10, 10, 10)
# 水平布局用于左右面板
horizontal_layout = QHBoxLayout()
horizontal_layout.setSpacing(10)
# 左侧控制面板
left_panel = self.create_panel()
horizontal_layout.addWidget(left_panel, 1)
# 将水平布局添加到垂直布局中
main_layout.addLayout(horizontal_layout)
# 状态栏
self.statusBar().showMessage("准备就绪")
# 添加弹性空间
main_layout.addStretch()
# 底部版权信息
copyright_label = QLabel(f"© {app_name} {version}")
copyright_label.setAlignment(Qt.AlignCenter)
copyright_label.setStyleSheet("""
color: #999;
font-size: 11px;
padding: 15px 0 5px 0;
border-top: 1px solid #eee;
margin-top: 10px;
""")
main_layout.addWidget(copyright_label)
# 设置扁平化样式
self.setStyleSheet("""
/* 主窗口 */
QMainWindow {
background-color: #f5f5f5;
font-family: 'Microsoft YaHei', 'Segoe UI', sans-serif;
}
/* 分组框 - 扁平化 */
QGroupBox {
font-size: 13px;
border: 1px solid #ddd;
border-radius: 6px;
margin-top: 8px;
padding-top: 8px;
background-color: white;
}
QGroupBox::title {
subcontrol-origin: margin;
left: 10px;
padding: 0 8px 0 8px;
color: #333;
}
/* 按钮 - 扁平化 */
QPushButton, QComboBox{
border: none;
border-radius: 4px;
padding: 13px 10px;
font-size: 15px;
color: white;
background-color: #6c757d;
}
QComboBox::drop-down {
border: none;
}
QComboBox QAbstractItemView {
outline: none;
background-color:white;
selection-background-color: transparent;
}
/* 特殊按钮样式 */
#browseBtn, #speedBtn{
background:white;
border: 1px solid #ddd;
color:blank;
}
#speedBtn{
font-size: 18px;
padding: 10px 10px;
}
#refreshBtn {
background-color: #28a745;
color: white;
border: none;
}
#startCastBtn {
background-color: #007bff;
color: white;
border: none;
}
#pauseCastBtn {
background-color: #ffc107;
color: white;
border: none;
}
#stopCastBtn {
background-color: #dc3545;
color: white;
border: none;
}
#startCastBtn:disabled,
#pauseCastBtn:disabled,
#stopCastBtn:disabled{
color: #999 !important;
background-color: #f5f5f5 !important;
}
/*音量图标*/
#muteBtn{
background-color:none;
}
/* 列表控件 */
QListWidget {
border: 1px solid #ddd;
border-radius: 4px;
background-color: white;
padding: 4px;
}
QListWidget::item {
padding: 6px 8px;
border-radius: 4px;
border-bottom: 1px solid #f0f0f0;
}
QListWidget::item:selected {
color: white;
background-color: #007bff;
}
/* 文本编辑框 */
QTextEdit {
border: 1px solid #ddd;
border-radius: 4px;
background-color: white;
font-size: 11.5px;
padding: 0 4px;
}
/* 标签 */
QLabel {
color: #333;
font-size: 12px;
}
/* 输入框 */
QLineEdit {
border: 1px solid #ddd;
border-radius: 4px;
padding: 0 8px;
font-size: 12px;
}
""")
def create_panel(self):
"""创建左侧控制面板(文件和设备控制合并)"""
panel = QWidget()
layout = QVBoxLayout(panel)
layout.setSpacing(10)
# ==================== 系统信息区域 ====================
system_group = QGroupBox("系统信息")
system_layout = QVBoxLayout()
system_layout.setSpacing(8)
# 获取本机IP
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
local_ip = s.getsockname()[0]
s.close()
except:
local_ip = "获取失败"
# 服务器状态
server_frame = QFrame()
server_layout = QHBoxLayout(server_frame)
server_layout.addWidget(QLabel("文件服务:"))
self.ip_label = QLabel(f"{local_ip}:{self.http_port}")
server_layout.addWidget(self.ip_label, 1)
system_layout.addWidget(server_frame)
# 文件服务状态
self.file_service_label = QLabel("就绪")
self.file_service_label.setStyleSheet("color: #28a745;")
server_layout.addWidget(self.file_service_label, 1)
system_group.setLayout(system_layout)
layout.addWidget(system_group)
# ==================== 文件和设备控制区域 ====================
control_group = QGroupBox("文件与设备控制")
control_layout = QVBoxLayout()
control_layout.setSpacing(12)
# 文件选择区域
file_frame = QFrame()
file_layout = QHBoxLayout(file_frame)
file_layout.setSpacing(8)
self.file_label = QLabel("未选择文件")
self.file_label.setWordWrap(True)
self.file_label.setMinimumHeight(25)
self.file_label.setStyleSheet("""
border: 1px solid #dee2e6;
border-radius: 4px;
padding-left: 5px;
""")
file_layout.addWidget(self.file_label, 1)
browse_btn = QPushButton("浏览文件")
browse_btn.setCursor(Qt.PointingHandCursor)
browse_btn.setFixedWidth(80)
browse_btn.setObjectName("browseBtn")
browse_btn.clicked.connect(self.browse_file)
file_layout.addWidget(browse_btn)
control_layout.addWidget(file_frame)
# 设备列表区域
device_frame = QFrame()
device_layout = QVBoxLayout(device_frame)
device_layout.setSpacing(8)
# 设备列表标题和刷新按钮
device_header = QHBoxLayout()
device_header.addWidget(QLabel("设备列表(单击选中):"))
device_header.addStretch()
device_layout.addLayout(device_header)
# 设备列表
self.device_list = QListWidget()
self.device_list.itemClicked.connect(self.select_device)
self.device_list.setMinimumHeight(100)
device_layout.addWidget(self.device_list)
control_layout.addWidget(device_frame)
# 播放控制按钮
playback_frame = QFrame()
playback_layout = QHBoxLayout(playback_frame)
playback_layout.setSpacing(8)
self.refresh_btn = QPushButton("刷新设备")
self.refresh_btn.setObjectName("refreshBtn")
self.refresh_btn.setCursor(Qt.PointingHandCursor)
self.refresh_btn.clicked.connect(self.refresh_devices)
# 播放速度选择框
self.speed_btn = QComboBox()
self.speed_btn.setObjectName("speedBtn")
speed = {"0.25x":0.25, "0.5x":0.5, "0.75x":0.75, "1x":1.0, "1.25x":1.25, "1.5x":1.5, "2x":2.0,"2.5x":2.50, "3x":3.0, "4x":4.0, "5x":5.0, "6x":6.0, "7x":7.0, "8x":8.0}
for key, value in speed.items():
self.speed_btn.addItem(key, value)
#默认选中1倍速度
self.speed_btn.setCurrentIndex(3)
self.speed_btn.setCursor(Qt.PointingHandCursor)
self.speed_btn.currentIndexChanged.connect(self.speed_selected)
self.start_btn = QPushButton("开始投屏")
self.start_btn.setObjectName("startCastBtn")
self.start_btn.setCursor(Qt.PointingHandCursor)
self.start_btn.setEnabled(False)
self.start_btn.clicked.connect(self.start_casting)
self.pause_btn = QPushButton("暂停投屏")
self.pause_btn.setObjectName("pauseCastBtn")
self.pause_btn.setCursor(Qt.PointingHandCursor)
self.pause_btn.clicked.connect(self.pause_casting)
self.pause_btn.setEnabled(False)
self.stop_btn = QPushButton("结束投屏")
self.stop_btn.setObjectName("stopCastBtn")
self.stop_btn.setCursor(Qt.PointingHandCursor)
self.stop_btn.clicked.connect(self.stop_casting)
self.stop_btn.setEnabled(False)
playback_layout.addWidget(self.refresh_btn)
playback_layout.addWidget(self.speed_btn)
playback_layout.addWidget(self.start_btn)
playback_layout.addWidget(self.pause_btn)
playback_layout.addWidget(self.stop_btn)
control_layout.addWidget(playback_frame)
# 音量控制
volume_frame = QFrame()
volume_layout = QHBoxLayout(volume_frame)
volume_layout.setSpacing(8)
volume_layout.addWidget(QLabel("音量:"))
self.volume_slider = QSlider(Qt.Horizontal)
self.volume_slider.setRange(0, 100)
self.volume_slider.setValue(50)
self.volume_slider.setCursor(Qt.PointingHandCursor)
self.volume_slider.valueChanged.connect(self.volume_changed)
volume_layout.addWidget(self.volume_slider, 1)
self.mute_btn = QPushButton("🔊")
self.mute_btn.setCheckable(True)
self.mute_btn.setFixedWidth(40)
self.mute_btn.setObjectName("muteBtn")
self.mute_btn.setCursor(Qt.PointingHandCursor)
self.mute_btn.clicked.connect(self.toggle_mute)
volume_layout.addWidget(self.mute_btn)
control_layout.addWidget(volume_frame)
control_group.setLayout(control_layout)
layout.addWidget(control_group, 1) # 主要区域占据更多空间
layout.addStretch()
return panel