Add sorting capability for "选择" and "材料名称" columns in the CheckboxTreeview: - Click column header to cycle through: asc (↑) → desc (↓) → unsort - Sort "选择" column by checkbox state (checked/unchecked) - Sort "材料名称" column alphabetically - Preserve checkbox states during sorting using move() instead of delete+insert - Separate event handlers for cell clicks and heading clicks Implementation details: - Added 6 new helper methods to CheckboxTreeview class - Store original headings to properly display sort arrows - Use identify_region() to distinguish between cell and heading clicks - Column index conversion (#1/#2) to column identifiers The sorting is a pure frontend feature with no database changes. Available to all users without permission restrictions. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
146 lines
3.4 KiB
Markdown
146 lines
3.4 KiB
Markdown
# 排序功能快速参考
|
||
|
||
## 用户使用指南
|
||
|
||
### 如何使用排序功能
|
||
|
||
1. **点击列头排序**
|
||
- 点击"选择"或"材料名称"列头
|
||
- 第一次点击:升序排列(显示 ↑)
|
||
- 第二次点击:降序排列(显示 ↓)
|
||
- 第三次点击:取消排序(箭头消失)
|
||
|
||
2. **切换排序列**
|
||
- 点击其他可排序列的列头
|
||
- 原列的排序箭头自动消失
|
||
- 新列显示排序箭头
|
||
|
||
3. **排序时复选框状态**
|
||
- 排序操作不会改变复选框的选中状态
|
||
- 所有项目的复选框状态在排序后保持不变
|
||
|
||
### 支持的列
|
||
|
||
✅ **可排序**:
|
||
- 选择
|
||
- 材料名称
|
||
|
||
❌ **不可排序**:
|
||
- 材料代码
|
||
- 规格
|
||
- 型号
|
||
- 负责人
|
||
|
||
## 开发者参考
|
||
|
||
### 核心方法
|
||
|
||
| 方法 | 功能 |
|
||
|------|------|
|
||
| `_store_original_headings()` | 存储原始列标题 |
|
||
| `_get_column_id_from_column_index()` | 列索引转列标识符 |
|
||
| `_on_heading_click()` | 处理表头点击事件 |
|
||
| `_toggle_sort()` | 切换排序状态 |
|
||
| `_sort_by_column()` | 执行排序操作 |
|
||
| `_update_heading_display()` | 更新列标题显示 |
|
||
|
||
### 排序状态变量
|
||
|
||
```python
|
||
self.sort_column = None # 当前排序列('选择' 或 '材料名称')
|
||
self.sort_direction = None # 排序方向('asc', 'desc', 或 None)
|
||
self.sortable_columns = ["选择", "材料名称"] # 可排序列白名单
|
||
self.original_headings = {} # 原始列标题文本
|
||
```
|
||
|
||
### 扩展排序到其他列
|
||
|
||
如果要添加新的可排序列,修改 `sortable_columns` 列表:
|
||
|
||
```python
|
||
self.sortable_columns = ["选择", "材料名称", "材料代码", "负责人"]
|
||
```
|
||
|
||
然后在 `_sort_by_column()` 方法中添加对应的排序逻辑:
|
||
|
||
```python
|
||
elif column_id == "材料代码":
|
||
items_data.sort(
|
||
key=lambda x: str(x['values'][2]) if len(x['values']) > 2 else "",
|
||
reverse=(direction == 'desc')
|
||
)
|
||
elif column_id == "负责人":
|
||
items_data.sort(
|
||
key=lambda x: str(x['values'][5]) if len(x['values']) > 5 else "",
|
||
reverse=(direction == 'desc')
|
||
)
|
||
```
|
||
|
||
### 排序逻辑
|
||
|
||
**"选择"列**:
|
||
```python
|
||
# 按复选框状态排序
|
||
items_data.sort(key=lambda x: x['checked'], reverse=(direction == 'desc'))
|
||
```
|
||
|
||
**"材料名称"列**:
|
||
```python
|
||
# 按字符串排序
|
||
items_data.sort(
|
||
key=lambda x: str(x['values'][1]) if len(x['values']) > 1 else "",
|
||
reverse=(direction == 'desc')
|
||
)
|
||
```
|
||
|
||
### 保持复选框状态的关键
|
||
|
||
使用 `move()` 方法而不是 `delete()` + `insert()`:
|
||
|
||
```python
|
||
# ✅ 正确:保留复选框状态
|
||
self.move(item_data['item_id'], '', 'end')
|
||
|
||
# ❌ 错误:会丢失复选框状态
|
||
# self.delete(item)
|
||
# self.insert("", tk.END, values=values)
|
||
```
|
||
|
||
## 故障排查
|
||
|
||
### 问题:点击列头没有反应
|
||
|
||
**可能原因**:
|
||
1. 点击的不是可排序列
|
||
2. 表格为空
|
||
|
||
**解决方法**:
|
||
- 确保点击的是"选择"或"材料名称"列
|
||
- 确保表格中有数据
|
||
|
||
### 问题:排序后复选框状态丢失
|
||
|
||
**可能原因**:
|
||
使用了 `delete()` + `insert()` 而不是 `move()`
|
||
|
||
**解决方法**:
|
||
检查 `_sort_by_column()` 方法中使用的是 `move()` 而不是 `delete()`
|
||
|
||
### 问题:排序箭头显示不正确
|
||
|
||
**可能原因**:
|
||
原始列标题没有正确存储
|
||
|
||
**解决方法**:
|
||
检查 `_store_original_headings()` 是否被正确调用(延迟100ms)
|
||
|
||
## 测试命令
|
||
|
||
```bash
|
||
# 运行排序功能测试
|
||
python tests/test_sorting.py
|
||
|
||
# 语法检查
|
||
python -m py_compile gui/material_validation_tab.py
|
||
```
|