2014-09-02 66 views
0

我想在QTreeView中显示“文件夹”和“文件”。文件夹旨在能够包含文件,并且由于这种关系,我希望文件夹项目能够显示在树视图中的文件项目上方。该视图应该是可排序的。如何确保文件夹项目始终显示在树形视图上的文件项目之上?如何使QTreeView总是先排序某个类别的项目?

在下面的代码提供了一种树形视图与文件夹和文件项的示例:

from PyQt5.QtCore import * 
from PyQt5.QtWidgets import * 
from PyQt5.QtGui import * 


def _create_item(text, is_folder): 
    item = QStandardItem(text) 
    item.setData(is_folder, Qt.UserRole) 
    return item 


def _folder_row(name, date): 
    return [_create_item(text, True) for text in (name, date)] 


def _file_row(name, date): 
    return [_create_item(text, False) for text in (name, date)] 


class _Window(QMainWindow): 
    def __init__(self): 
     super().__init__() 

     widget = QWidget() 
     self.__view = QTreeView() 
     layout = QVBoxLayout(widget) 
     layout.addWidget(self.__view) 
     self.setCentralWidget(widget) 

     model = QStandardItemModel() 
     model.appendRow(_file_row('File #1', '01.09.2014')) 
     model.appendRow(_folder_row('Folder #1', '01.09.2014')) 
     model.appendRow(_folder_row('Folder #2', '02.09.2014')) 
     model.appendRow(_file_row('File #2', '03.09.2014')) 
     model.setHorizontalHeaderLabels(['Name', 'Date']) 
     self.__view.setModel(model) 
     self.__view.setSortingEnabled(True) 


app = QApplication([]) 
w = _Window() 
w.show() 
app.exec_() 

回答

3

一种解决方案是包装在一个QSortFilterProxyModel模型,并重新实现代理的lessThan方法使其使得夹项目始终放置在文件项目之前:

from PyQt5.QtCore import * 
from PyQt5.QtWidgets import * 
from PyQt5.QtGui import * 


def _create_item(text, is_folder): 
    item = QStandardItem(text) 
    item.setData(is_folder, Qt.UserRole) 
    return item 


def _folder_row(name, date): 
    return [_create_item(text, True) for text in (name, date)] 


def _file_row(name, date): 
    return [_create_item(text, False) for text in (name, date)] 


class _SortProxyModel(QSortFilterProxyModel): 
    """Sorting proxy model that always places folders on top.""" 
    def __init__(self, model): 
     super().__init__() 
     self.setSourceModel(model) 

    def lessThan(self, left, right): 
     """Perform sorting comparison. 

     Since we know the sort order, we can ensure that folders always come first. 
     """ 
     left_is_folder = left.data(Qt.UserRole) 
     left_data = left.data(Qt.DisplayRole) 
     right_is_folder = right.data(Qt.UserRole) 
     right_data = right.data(Qt.DisplayRole) 
     sort_order = self.sortOrder() 

     if left_is_folder and not right_is_folder: 
      result = sort_order == Qt.AscendingOrder 
     elif not left_is_folder and right_is_folder: 
      result = sort_order != Qt.AscendingOrder 
     else: 
      result = left_data < right_data 
     return result 


class _Window(QMainWindow): 
    def __init__(self): 
     super().__init__() 

     widget = QWidget() 
     self.__view = QTreeView() 
     layout = QVBoxLayout(widget) 
     layout.addWidget(self.__view) 
     self.setCentralWidget(widget) 

     model = QStandardItemModel() 
     model.appendRow(_file_row('File #1', '01.09.2014')) 
     model.appendRow(_folder_row('Folder #1', '01.09.2014')) 
     model.appendRow(_folder_row('Folder #2', '02.09.2014')) 
     model.appendRow(_file_row('File #2', '03.09.2014')) 
     model.setHorizontalHeaderLabels(['Name', 'Date']) 
     proxy_model = _SortProxyModel(model) 
     self.__view.setModel(proxy_model) 
     self.__view.setSortingEnabled(True) 


app = QApplication([]) 
w = _Window() 
w.show() 
app.exec_() 
相关问题