This commit is contained in:
Irony 2018-12-27 22:26:02 +08:00
parent b7b998df14
commit a49a423507
4 changed files with 162 additions and 10 deletions

View file

@ -3,9 +3,85 @@
## 1. Custom Widget Item
[Run CustomWidgetItem.py](CustomWidgetItem.py)
use `setIndexWidget(QModelIndex, QWidget)` to set custom `QWidget`
![CustomWidgetItem](ScreenShot/CustomWidgetItem.png)
## 2. Custom Widget Sort Item
[Run CustomWidgetSortItem.py](CustomWidgetSortItem.py)
![CustomWidgetSortItem](ScreenShot/CustomWidgetSortItem.gif)
1. set QListView proxy model, use `QSortFilterProxyModel`
2. rewrite `lessThan` method to sort
![CustomWidgetSortItem](ScreenShot/CustomWidgetSortItem.gif)
## 3, Custom Role And Sort
[Run SortItemByRole.py](SortItemByRole.py)
Demand:
1. 5 categories(Tang, Song, Yuan, Ming, Qing) and Unclassified
2. selected Tang, the result is Tang, Song, Yuan, Ming, Qing, Unclassified
3. selected Song, the result is Song, Tang, Yuan, Ming, Qing, Unclassified
4. selected Yuan, the result is Yuan, Tang, Song, Ming, Qing, Unclassified
5. Cancel sorting then Restore, like: Unclassified, Tang, Tang, Ming, Qing, Unclassified, Song, Yuan, Unclassified
Method:
1. define `IdRole = Qt.UserRole + 1` Used to restore default sort
2. define `ClassifyRole = Qt.UserRole + 2` Used for sorting by sorting number
3. define 5 classify id
```python
NameDict = {
'Tang': ['Tang', 0],
'Song': ['Song', 1],
'Yuan': ['Yuan', 2],
'Ming': ['Ming', 3],
'Qing': ['Qing', 4],
}
IndexDict = {
0: 'Tang',
1: 'Song',
2: 'Yuan',
3: 'Ming',
4: 'Qing',
}
```
4. item `setData(id, IdRole)` Used to restore default sort
5. item `setData(cid, ClassifyRole)` Used to record classification
6. inherit `QSortFilterProxyModel` and add `setSortIndex(self, index)` mthod, The purpose is to keep some classify always top
```python
def setSortIndex(self, index):
self._topIndex = index
```
7. inherit `QSortFilterProxyModel` and rewrite `lessThan` mthod, if classify id is equal to top id, then modify it -1
```python
if self.sortRole() == ClassifyRole and \
source_left.column() == self.sortColumn() and \
source_right.column() == self.sortColumn():
# get classify id
leftIndex = source_left.data(ClassifyRole)
rightIndex = source_right.data(ClassifyRole)
# AscendingOrder
if self.sortOrder() == Qt.AscendingOrder:
# keep always top
if leftIndex == self._topIndex:
leftIndex = -1
if rightIndex == self._topIndex:
rightIndex = -1
return leftIndex < rightIndex
```
8. restore default sort
```python
self.fmodel.setSortRole(IdRole)
self.fmodel.sort(0)
```
9. sort by classify id, must reset `setSortRole` to other
```python
self.fmodel.setSortIndex(1)
self.fmodel.setSortRole(IdRole)
self.fmodel.setSortRole(ClassifyRole)
self.fmodel.sort(0)
```
![SortItemByRole](ScreenShot/SortItemByRole.gif)

View file

@ -3,9 +3,85 @@
## 1、显示自定义Widget
[运行 CustomWidgetItem.py](CustomWidgetItem.py)
通过设置 `setIndexWidget(QModelIndex, QWidget)` 可以设置自定义 `QWidget`
![CustomWidgetItem](ScreenShot/CustomWidgetItem.png)
## 2、显示自定义Widget并排序
[运行 CustomWidgetSortItem.py](CustomWidgetSortItem.py)
![CustomWidgetSortItem](ScreenShot/CustomWidgetSortItem.gif)
1. 对QListView设置代理 `QSortFilterProxyModel`
2. 重写model的 `lessThan` 方法进行排序
![CustomWidgetSortItem](ScreenShot/CustomWidgetSortItem.gif)
## 3、自定义角色排序
[运行 SortItemByRole.py](SortItemByRole.py)
需求:
1. 5种分类唐、宋、元、明、清 和 未分类
2. 选中唐则按照 唐、宋、元、明、清、未分类排序
3. 选中宋则按照 宋、唐、元、明、清、未分类排序
4. 选中元则按照 元、唐、宋、明、清、未分类排序
5. 取消排序则恢复到加载时候顺序,如:未分类、唐、唐、明、清、未分类、宋、元、未分类
思路:
1. 定义`IdRole = Qt.UserRole + 1` 用于恢复默认排序
2. 定义`ClassifyRole = Qt.UserRole + 2` 用于按照分类序号排序
3. 定义5种分类的id
```python
NameDict = {
'唐': ['Tang', 0],
'宋': ['Song', 1],
'元': ['Yuan', 2],
'明': ['Ming', 3],
'清': ['Qing', 4],
}
IndexDict = {
0: '唐',
1: '宋',
2: '元',
3: '明',
4: '清',
}
```
4. item设置 `setData(id, IdRole)` 用于恢复默认排序
5. item设置 `setData(cid, ClassifyRole)` 用于标识该item的分类
6. 继承 `QSortFilterProxyModel` 增加 `setSortIndex(self, index)` 方法, 目的在于记录要置顶不参与排序的分类ID
```python
def setSortIndex(self, index):
self._topIndex = index
```
7. 继承 `QSortFilterProxyModel` 重写 `lessThan` 方法, 判断分类ID是否等于要置顶的ID, 如果是则修改为-1, 这样就永远在最前面
```python
if self.sortRole() == ClassifyRole and \
source_left.column() == self.sortColumn() and \
source_right.column() == self.sortColumn():
# 获取左右两个的分类
leftIndex = source_left.data(ClassifyRole)
rightIndex = source_right.data(ClassifyRole)
# 升序
if self.sortOrder() == Qt.AscendingOrder:
# 保持在最前面
if leftIndex == self._topIndex:
leftIndex = -1
if rightIndex == self._topIndex:
rightIndex = -1
return leftIndex < rightIndex
```
8. 恢复默认排序
```python
self.fmodel.setSortRole(IdRole) # 必须设置排序角色为ID
self.fmodel.sort(0) # 排序第一列按照ID升序
```
9. 根据分类排序, 这里要注意要先通过 `setSortRole` 设置其它角色再设置目标角色
```python
self.fmodel.setSortIndex(1)
self.fmodel.setSortRole(IdRole)
self.fmodel.setSortRole(ClassifyRole)
self.fmodel.sort(0)
```
![SortItemByRole](ScreenShot/SortItemByRole.gif)

View file

@ -11,7 +11,7 @@ Created on 2018年12月27日
"""
from random import choice
from PyQt5.QtCore import QSortFilterProxyModel, Qt, QTimer
from PyQt5.QtCore import QSortFilterProxyModel, Qt
from PyQt5.QtGui import QStandardItem, QStandardItemModel
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QListView, QPushButton
@ -49,7 +49,7 @@ class SortFilterProxyModel(QSortFilterProxyModel):
# 保持在最前面
if leftIndex == self._topIndex:
leftIndex = -1
elif rightIndex == self._topIndex:
if rightIndex == self._topIndex:
rightIndex = -1
return leftIndex < rightIndex
@ -71,7 +71,6 @@ IndexDict = {
3: '',
4: '',
}
BigIndex = 100
IdRole = Qt.UserRole + 1 # 用于恢复排序
ClassifyRole = Qt.UserRole + 2 # 用于按照分类序号排序
@ -102,11 +101,12 @@ class Window(QWidget):
def sortByClassify(self):
self.fmodel.setSortIndex(NameDict.get(
self.sender().text(), ['', BigIndex])[1])
self.restoreSort()
self.sender().text(), ['', 100])[1])
# self.restoreSort()
self.fmodel.setSortRole(IdRole)
# 按照给定的分类排序(这里注意还要按照把给定分类的放在最前面)
self.fmodel.setSortRole(ClassifyRole)
QTimer.singleShot(100, lambda: self.fmodel.sort(0))
self.fmodel.sort(0)
def _initItems(self):
# 初始化Items
@ -120,7 +120,7 @@ class Window(QWidget):
classifies = [v[1] for v in NameDict.values()]
for i in range(5):
# 添加5个100, 用于模拟没有分类, 排序的时候就显示在最后面
classifies.append(BigIndex)
classifies.append(100)
print(classifies) # [4, 2, 0, 3, 1, 100, 100, 100, 100, 100]
# 生成50个Item

View file

@ -6,7 +6,7 @@ https://pyqt5.com 社区是专门针对PyQt5学习和提升开设的博客网站
## 目录
| 分类 | 控件 |
| 分类 | 控件 |
|:-------|:-------|
| ActiveX | [QAxWidget](QAxWidget)
| 日历 | [QCalendarWidget](QCalendarWidget)