功能做完了,界面不能太寒碜。
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
┌──────────────────────────────────────────────────────────────────┐
│ 图片剪切归档管理工具 │
├──────────────────────────────────────────────────────────────────┤
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ 客户:[______] 操作人:[______] 批次号:[______] [清除][配置][归档] │
│ └────────────────────────────────────────────────────────────┘ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ 客户:[______] 日期范围:[📅至📅] 操作人:[______] [查询][刷新] │ │
│ └────────────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────┬──────────────────────────┐ │
│ │ 图片归档一览表 │ 预览 │ │
│ │ ┌─────────────────────────────┐│ ┌──────────────────────┐ │ │
│ │ │ 日期│客户│操作人│批次号│文件名││ │ │ │ │
│ │ ├─────┼────┼──────┼──────┼─────┤│ │ [缩略图区域] │ │ │
│ │ │ ... │ ...│ ... │ ... │ ... ││ │ │ │ │
│ │ └─────────────────────────────┘│ └──────────────────────┘ │ │
│ │ │ 操作日志 │ │
│ │ │ ┌──────────────────────┐│ │
│ │ │ │ [日志文本区] ││ │
│ │ │ └──────────────────────┘│ │
│ └─────────────────────────────────┴──────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
八、踩坑记录
-
qt-material + PyInstaller onefile :资源写入路径要用
tempfile.gettempdir(),否则无写权限 -
日历弹出被遮挡 :确保
QDateEdit所在的窗口层级足够高 -
表格行选中状态 :
SelectRows+SingleSelection组合使用,效果最好 -
清除按钮不清除操作员 :操作员只能通过登录框修改,
clear_inputs()只清客户和批次号 -
只读字段仍可复制 :
setReadOnly(True)只是不能编辑,但用户仍可选中复制文字,如需完全禁止可加setFocusPolicy(Qt.FocusPolicy.NoFocus)
下篇预告
下一篇写打包优化与体积控制:PyInstaller配置、依赖精简、UPX压缩。
如果对UI美化有不同思路,评论区聊。