widget_file_list/card_list_widget.py

264 lines
9.2 KiB
Python
Raw Permalink Normal View History

2025-02-14 15:00:10 +08:00
from PySide6.QtWidgets import (QApplication, QWidget, QListWidget, QListWidgetItem,
QStyledItemDelegate, QVBoxLayout, QStyle, QMenu)
from PySide6.QtCore import Qt, QRect, QSize
from PySide6.QtGui import QPainter, QPen, QColor, QFont, QPainterPath, QLinearGradient
import subprocess
import os
from datetime import date
import sys
class CardData:
"""卡片数据结构"""
def __init__(self, name: str, date: str, description: str):
self.name = name
self.date = date
self.description = description
self.activated = False # 添加激活状态标志
class CardItemDelegate(QStyledItemDelegate):
"""自定义委托类来绘制卡片样式"""
def paint(self, painter: QPainter, option, index):
painter.setRenderHint(QPainter.Antialiasing) # 启用抗锯齿
painter.save()
# 获取数据
item = index.data(Qt.UserRole)
if not isinstance(item, CardData):
print(f"Warning: Invalid data type: {type(item)}")
return
# 绘制卡片背景
rect = option.rect
rect.adjust(8, 4, -8, -4) # 调整边距
# 创建圆角路径
path = QPainterPath()
path.addRoundedRect(rect, 8, 8)
# 绘制阴影
shadow_color = QColor(0, 0, 0, 30)
for i in range(5):
shadow_rect = rect.adjusted(0, i, 0, i)
shadow_path = QPainterPath()
shadow_path.addRoundedRect(shadow_rect, 8, 8)
painter.fillPath(shadow_path, shadow_color)
# 绘制卡片背景
if item.activated: # 激活状态
gradient = QLinearGradient(rect.topLeft(), rect.bottomLeft())
gradient.setColorAt(0, QColor(40, 70, 45))
gradient.setColorAt(1, QColor(45, 80, 50))
painter.fillPath(path, gradient)
painter.setPen(QPen(QColor(60, 180, 90), 2))
elif option.state & QStyle.State_Selected:
gradient = QLinearGradient(rect.topLeft(), rect.bottomLeft())
gradient.setColorAt(0, QColor(45, 45, 55))
gradient.setColorAt(1, QColor(55, 55, 65))
painter.fillPath(path, gradient)
painter.setPen(QPen(QColor(70, 130, 180), 2))
else:
painter.fillPath(path, QColor(35, 35, 40)) # 深色背景
painter.setPen(QPen(QColor(60, 60, 65)))
painter.drawPath(path)
# 设置字体
name_font = QFont("Microsoft YaHei", 10)
name_font.setBold(True)
normal_font = QFont("Microsoft YaHei", 9)
# 计算文本区域
padding = 15
name_rect = rect.adjusted(padding, padding, -padding, 0)
name_rect.setHeight(25)
date_rect = QRect(name_rect)
date_rect.translate(0, name_rect.height())
desc_rect = QRect(date_rect)
desc_rect.translate(0, date_rect.height())
desc_rect.setHeight(40)
# 绘制文本
painter.setFont(name_font)
painter.setPen(Qt.white) # 白色文字
painter.drawText(name_rect, Qt.AlignLeft | Qt.AlignVCenter, item.name)
painter.setFont(normal_font)
painter.setPen(QColor(180, 180, 180)) # 浅灰色文字
painter.drawText(date_rect, Qt.AlignLeft | Qt.AlignVCenter, item.date)
painter.setPen(QColor(160, 160, 160)) # 描述文字颜色
painter.drawText(desc_rect, Qt.AlignLeft | Qt.AlignTop | Qt.TextWordWrap,
item.description)
painter.restore()
def sizeHint(self, option, index):
return QSize(380, 130) # 略微增加高度
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("卡片列表示例")
self.resize(400, 600)
# 设置窗口背景色
self.setStyleSheet("background-color: #1e1e1e;")
# 创建布局
layout = QVBoxLayout(self)
layout.setContentsMargins(10, 10, 10, 10)
layout.setSpacing(0)
# 创建列表控件
self.list_widget = QListWidget(self)
self.list_widget.setSpacing(10) # 增加卡片间距
self.list_widget.setResizeMode(QListWidget.Adjust)
self.list_widget.setUniformItemSizes(False)
self.list_widget.setViewMode(QListWidget.ListMode)
self.list_widget.setVerticalScrollMode(QListWidget.ScrollPerPixel)
self.list_widget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
# 设置委托
delegate = CardItemDelegate(self.list_widget)
self.list_widget.setItemDelegate(delegate)
# 设置样式
self.list_widget.setStyleSheet("""
QListWidget {
background-color: #1e1e1e;
border: none;
outline: none;
}
QListWidget::item {
background-color: transparent;
padding: 4px;
}
QListWidget::item:selected {
background-color: transparent;
}
QScrollBar:vertical {
border: none;
background: #1e1e1e;
width: 8px;
margin: 0px;
}
QScrollBar::handle:vertical {
background: #404040;
min-height: 20px;
border-radius: 4px;
}
QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {
height: 0px;
}
QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
background: none;
}
""")
layout.addWidget(self.list_widget)
# 添加示例数据
for i in range(1, 11):
data = CardData(
name=f"项目 {i}",
date=date.today().strftime("%Y-%m-%d"),
description=f"这是项目 {i} 的详细描述信息,可以包含多行文本内容。这是一个较长的描述,用于测试换行效果。"
)
self.add_card_item(data)
# 连接信号
self.list_widget.itemDoubleClicked.connect(self.on_item_double_clicked)
self.list_widget.customContextMenuRequested.connect(self.show_context_menu)
self.list_widget.setContextMenuPolicy(Qt.CustomContextMenu)
def add_card_item(self, data: CardData):
"""添加卡片项目"""
item = QListWidgetItem(self.list_widget)
item.setData(Qt.UserRole, data)
# 设置item大小
item.setSizeHint(QSize(380, 120))
# 设置item可选
item.setFlags(Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable)
def on_item_double_clicked(self, item):
"""双击处理"""
data = item.data(Qt.UserRole)
if isinstance(data, CardData):
data.activated = not data.activated # 切换激活状态
self.list_widget.viewport().update() # 刷新视图
def show_context_menu(self, position):
"""显示右键菜单"""
item = self.list_widget.itemAt(position)
if not item:
return
menu = QMenu(self)
# 创建动作
send_action = menu.addAction("发送到设备")
edit_action = menu.addAction("修改")
delete_action = menu.addAction("删除")
show_in_explorer_action = menu.addAction("在资源管理器中显示")
# 显示菜单并获取选择的动作
action = menu.exec(self.list_widget.viewport().mapToGlobal(position))
if not action:
return
# 处理菜单动作
if action == send_action:
self.send_to_device(item)
elif action == edit_action:
self.edit_item(item)
elif action == delete_action:
self.delete_item(item)
elif action == show_in_explorer_action:
self.show_in_explorer(item)
def send_to_device(self, item):
"""发送到设备"""
data = item.data(Qt.UserRole)
print(f"发送到设备: {data.name}")
# TODO: 实现发送到设备的具体逻辑
def edit_item(self, item):
"""编辑项目"""
data = item.data(Qt.UserRole)
print(f"编辑项目: {data.name}")
# TODO: 实现编辑对话框
def delete_item(self, item):
"""删除项目"""
row = self.list_widget.row(item)
self.list_widget.takeItem(row)
def show_in_explorer(self, item):
"""在资源管理器中显示"""
data = item.data(Qt.UserRole)
# 这里假设每个项目都有一个关联的文件路径
# TODO: 需要在CardData中添加文件路径属性
file_path = os.path.abspath(".") # 示例使用当前目录
if os.name == 'nt': # Windows
subprocess.run(['explorer', '/select,', file_path])
elif os.name == 'posix': # macOS 和 Linux
if sys.platform == 'darwin': # macOS
subprocess.run(['open', '-R', file_path])
else: # Linux
subprocess.run(['xdg-open', os.path.dirname(file_path)])
if __name__ == "__main__":
app = QApplication(sys.argv)
# 设置默认字体
font = QFont("Microsoft YaHei", 9)
app.setFont(font)
window = MainWindow()
window.show()
sys.exit(app.exec())