264 lines
9.2 KiB
Python
264 lines
9.2 KiB
Python
|
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())
|