2014-09-02 39 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_() 
相關問題