图片归档工具:UI美化与用户体验优化(qt-material + QDateEdit)

功能做完了,界面不能太寒碜。

qt-material主题、日历弹出选择、表格行选择、清除按钮------一篇讲完。

一、概述

本文介绍图片归档工具的UI美化和用户体验优化:

功能 技术方案 效果
主题美化 qt-material 界面更现代
日历选择 QDateEdit.setCalendarPopup() 日期选择更友好
行选择模式 QTableWidget.SelectionBehavior 整行选中更直观
清除按钮 一键清空输入框 操作更便捷

二、qt-material 主题应用

2.1 安装

bash

复制代码
pip install qt-material

2.2 配置(含onefile打包修复)

python

复制代码
import tempfile
import qt_material.resources.generate as _qt_material_gen

# ========== PyInstaller onefile 模式修复 ==========
_qt_material_gen.RESOURCES_PATH = os.path.join(tempfile.gettempdir(), '.qt_material')
os.makedirs(_qt_material_gen.RESOURCES_PATH, exist_ok=True)

from qt_material import apply_stylesheet

def main():
    app = QApplication(sys.argv)
    
    # 应用主题
    apply_stylesheet(app, theme='dark_teal.xml', extra={'font_size': '14px'})
    
    window = MainWindow()
    window.show()
    return app.exec()

为什么要把资源路径指向临时目录 :PyInstaller onefile模式下,exe运行时解压到临时目录,但qt-material默认会在当前目录写入资源文件------当前目录可能没有写权限。改到tempfile.gettempdir()完美解决。

2.3 可用主题列表

深色主题 浅色主题
dark_amber.xml light_amber.xml
dark_blue.xml light_blue.xml
dark_cyan.xml light_cyan.xml
dark_teal.xml light_teal.xml
dark_pink.xml light_pink.xml
dark_purple.xml light_purple.xml

本项目使用 dark_teal.xml

2.4 额外参数

python

复制代码
apply_stylesheet(
    app, 
    theme='dark_teal.xml', 
    extra={
        'font_size': '14px',                           # 字体大小
        'ripple_color': 'rgba(255, 255, 255, 0.1)',   # 水波纹颜色
    }
)

三、日历弹出选择器(QDateEdit)

3.1 实现

python

复制代码
def create_query_section(self, parent_layout):
    # 开始日期
    self.start_date = QDateEdit()
    self.start_date.setDate(QDate.currentDate().addDays(-30))  # 默认30天前
    self.start_date.setDisplayFormat("yyyy-MM-dd")
    self.start_date.setCalendarPopup(True)   # 启用日历弹出
    self.start_date.setFixedWidth(120)
    
    # 结束日期
    self.end_date = QDateEdit()
    self.end_date.setDate(QDate.currentDate())   # 默认今天
    self.end_date.setDisplayFormat("yyyy-MM-dd")
    self.end_date.setCalendarPopup(True)   # 启用日历弹出
    self.end_date.setFixedWidth(120)

3.2 关键属性

属性 作用
setCalendarPopup(True) 点击时弹出日历控件
setDisplayFormat("yyyy-MM-dd") 日期显示格式
setDate(QDate.currentDate()) 设置默认日期

四、表格行选择模式(QTableWidget)

4.1 配置

python

复制代码
def create_content_section(self, parent_layout):
    self.table = QTableWidget()
    self.table.setColumnCount(8)
    self.table.setHorizontalHeaderLabels([
        "日期", "客户", "操作人", "批次号", "文件名", "存储路径", "状态", "操作时间"
    ])
    
    # 行选择 + 单选
    self.table.setSelectionBehavior(QTableWidget.SelectionBehavior.SelectRows)
    self.table.setSelectionMode(QTableWidget.SelectionMode.SingleSelection)
    
    # 连接行点击事件
    self.table.cellClicked.connect(self.on_table_row_click)

4.2 选择模式对比

setSelectionBehavior

模式 说明
SelectRows 选中整行(推荐)
SelectColumns 选中整列
SelectItems 选中单个单元格

setSelectionMode

模式 说明
SingleSelection 单选
MultiSelection 多选
ExtendedSelection Ctrl/Shift扩展选择
NoSelection 禁止选择

4.3 行点击处理

python

复制代码
def on_table_row_click(self, row, column):
    """点击表格行时加载缩略图"""
    dst_path = self.table.item(row, 5).text()
    self.load_thumbnail(dst_path)

五、清除按钮

5.1 实现

python

复制代码
def clear_inputs(self):
    """清除客户和批次号输入框"""
    self.customer_input.clear()
    self.lot_no_input.clear()

5.2 工具栏布局

python

复制代码
def create_archive_section(self, parent_layout):
    # 输入框...
    self.clear_btn = QPushButton("清除")
    self.clear_btn.clicked.connect(self.clear_inputs)
    self.clear_btn.setFixedWidth(80)
    
    self.config_btn = QPushButton("配置")
    self.config_btn.clicked.connect(self.show_config_dialog)
    self.config_btn.setFixedWidth(80)
    
    self.archive_btn = QPushButton("归档")
    self.archive_btn.clicked.connect(self.execute_archive)
    self.archive_btn.setFixedWidth(80)
    
    # 布局:客户 → 操作人 → 批次号 → 拉伸 → 清除 → 配置 → 归档
    layout.addWidget(QLabel("客户:"))
    layout.addWidget(self.customer_input)
    layout.addWidget(QLabel("操作人:"))
    layout.addWidget(self.operator_input)
    layout.addWidget(QLabel("批次号:"))
    layout.addWidget(self.lot_no_input)
    layout.addStretch()
    layout.addWidget(self.clear_btn)
    layout.addWidget(self.config_btn)
    layout.addWidget(self.archive_btn)

六、操作员只读字段

6.1 设置只读

python

复制代码
self.operator_input = QLineEdit()
self.operator_input.setPlaceholderText("操作人")
self.operator_input.setFixedWidth(120)
self.operator_input.setReadOnly(True)   # 只能通过登录框设置

6.2 登录后填充

python

复制代码
def show_login_dialog(self):
    dialog = LoginDialog(self.config_manager, self)
    result = dialog.exec()
    if result == QDialog.DialogCode.Accepted:
        operator = dialog.operator_edit.text().strip()
        self.operator_input.setText(operator)   # 自动填入
    else:
        sys.exit(0)

七、界面布局总览

text

复制代码
┌──────────────────────────────────────────────────────────────────┐
│ 图片剪切归档管理工具                                               │
├──────────────────────────────────────────────────────────────────┤
│  ┌────────────────────────────────────────────────────────────┐  │
│  │ 客户:[______] 操作人:[______] 批次号:[______]  [清除][配置][归档] │
│  └────────────────────────────────────────────────────────────┘ │
│  ┌────────────────────────────────────────────────────────────┐ │
│  │ 客户:[______] 日期范围:[📅至📅] 操作人:[______] [查询][刷新] │ │
│  └────────────────────────────────────────────────────────────┘ │
│  ┌─────────────────────────────────┬──────────────────────────┐ │
│  │ 图片归档一览表                   │ 预览                      │ │
│  │ ┌─────────────────────────────┐│ ┌──────────────────────┐  │ │
│  │ │ 日期│客户│操作人│批次号│文件名││ │                      │  │ │
│  │ ├─────┼────┼──────┼──────┼─────┤│ │    [缩略图区域]      │  │ │
│  │ │ ... │ ...│ ... │ ...  │ ... ││ │                      │  │ │
│  │ └─────────────────────────────┘│ └──────────────────────┘  │ │
│  │                                  │ 操作日志                 │ │
│  │                                  │ ┌──────────────────────┐│ │
│  │                                  │ │ [日志文本区]          ││ │
│  │                                  │ └──────────────────────┘│ │
│  └─────────────────────────────────┴──────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘

八、踩坑记录

  1. qt-material + PyInstaller onefile :资源写入路径要用tempfile.gettempdir(),否则无写权限

  2. 日历弹出被遮挡 :确保QDateEdit所在的窗口层级足够高

  3. 表格行选中状态SelectRows + SingleSelection组合使用,效果最好

  4. 清除按钮不清除操作员 :操作员只能通过登录框修改,clear_inputs()只清客户和批次号

  5. 只读字段仍可复制setReadOnly(True)只是不能编辑,但用户仍可选中复制文字,如需完全禁止可加setFocusPolicy(Qt.FocusPolicy.NoFocus)

下篇预告

下一篇写打包优化与体积控制:PyInstaller配置、依赖精简、UPX压缩。

如果对UI美化有不同思路,评论区聊。