diff --git a/QListView/README.en.md b/QListView/README.en.md index d9437ef..779a925 100644 --- a/QListView/README.en.md +++ b/QListView/README.en.md @@ -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) \ No newline at end of file +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) \ No newline at end of file diff --git a/QListView/README.md b/QListView/README.md index 9b4a8ce..74d7644 100644 --- a/QListView/README.md +++ b/QListView/README.md @@ -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) \ No newline at end of file +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) \ No newline at end of file diff --git a/QListView/SortItemByRole.py b/QListView/SortItemByRole.py index 74bb241..5239d40 100644 --- a/QListView/SortItemByRole.py +++ b/QListView/SortItemByRole.py @@ -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 diff --git a/README.md b/README.md index e42d6ea..6fe57e8 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ https://pyqt5.com 社区是专门针对PyQt5学习和提升开设的博客网站 ## 目录 -| 分类 | 控件名 | +| 分类 | 控件 | |:-------|:-------| | ActiveX | [QAxWidget](QAxWidget) | 日历 | [QCalendarWidget](QCalendarWidget)