如何在QTableView列中添加QTreeView

时间:2015-08-15 06:20:34

标签: python pyqt pyqt4 qtableview

我是PyQt的新手,我正在开发一个包含QTableView的项目,其中一列显示系统路径。我想添加一个QTreeView,以便用户点击 + > 按钮展开路径下的内容。

这是我的基本实现:

from PyQt4 import QtGui
from PyQt4 import QtCore

class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)

        self.resize(600,400)
        self.setWindowTitle("My Basic Treeview")

        self.treeview = QtGui.QTreeView(self)

        self.treeview.model = QtGui.QFileSystemModel()
        self.treeview.model.setRootPath('/opt')
        self.treeview.setModel(self.treeview.model)
        self.treeview.setColumnWidth(0, 200)

        self.setCentralWidget(self.treeview)

if __name__ == '__main__':
    import sys
    app = QtGui.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())

虽然在上面的例子中,我获取了所有文件夹,但我只想要/opt路径及其下面的文件夹。

import operator
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class MyWindow(QWidget):
    def __init__(self, data_list, header, *args):
        QWidget.__init__(self, *args)
        # setGeometry(x_pos, y_pos, width, height)
        self.setGeometry(300, 200, 570, 450)
        self.setWindowTitle("Click on column title to sort")
        table_model = MyTableModel(self, data_list, header)
        table_view = QTableView()
        table_view.setModel(table_model)
        # set font
        font = QFont("Courier New", 14)
        table_view.setFont(font)
        # set column width to fit contents (set font first!)
        table_view.resizeColumnsToContents()
        # enable sorting
        table_view.setSortingEnabled(True)
        layout = QVBoxLayout(self)
        layout.addWidget(table_view)
        self.setLayout(layout)

class MyTableModel(QAbstractTableModel):
    def __init__(self, parent, mylist, header, *args):
        QAbstractTableModel.__init__(self, parent, *args)
        self.mylist = mylist
        self.header = header

    def rowCount(self, parent):
        return len(self.mylist)

    def columnCount(self, parent):
        return len(self.mylist[0])

    def data(self, index, role):
        if not index.isValid():
            return None
        elif role != Qt.DisplayRole:
            return None
        return self.mylist[index.row()][index.column()]

    def headerData(self, col, orientation, role):
        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            return self.header[col]
        return None

# the solvent data ...
header = ['Name', ' Email', ' Status', ' Path']
# use numbers for numeric data to sort properly
data_list = [
('option_A', 'zyro@email.com', 'Not Copied', '/Opt'),
('option_B', 'zyro@email.com', 'Not Copied', '/Users'),
]
app = QApplication([])
win = MyWindow(data_list, header)
win.show()
app.exec_()

视觉示例:

enter image description here

1 个答案:

答案 0 :(得分:5)

我认为你的问题可分为两部分:

  1. 如何在 QTreeView 中显示/opt路径及其子项,但不显示其兄弟姐妹。换句话说,如何在 QTreeView 中显示根目录;

  2. 如何将 QTreeView 添加到 QTableView

  3. 1。如何在QTreeView中包含根目录:

    QTreeView 的根目录是在视图中显示内容的目录。在调用方法setRootIndex时设置它。根据{{​​3}}:

      

    您无法显示invisibleRootItem,因为它只是一个假的项目,只能使用等效的空QModelIndex。

    解决方法是将根目录设置为/opt的父目录,并使用 QSortFilterProxyModel 的子类过滤掉/opt的兄弟。请注意,我还重新实现了sizeHint方法,该方法是调整 QTableView 行的大小所必需的:

    from PyQt4 import QtGui, QtCore
    import os
    
    class MyQTreeView(QtGui.QTreeView):
    
        def __init__(self, path, parent=None):
            super(MyQTreeView, self).__init__(parent)
    
            ppath = os.path.dirname(path) # parent of path
            self.setFrameStyle(0)
    
            #---- File System Model ----
    
            sourceModel = QtGui.QFileSystemModel()
            sourceModel.setRootPath(ppath)
    
            #---- Filter Proxy Model ----
    
            proxyModel = MyQSortFilterProxyModel(path)
            proxyModel.setSourceModel(sourceModel)
    
            #---- Filter Proxy Model ----
    
            self.setModel(proxyModel)
            self.setHeaderHidden(True)
            self.setRootIndex(proxyModel.mapFromSource(sourceModel.index(ppath)))  
    
            #--- Hide All Header Sections Except First ----
    
            header = self.header()
            for sec in range(1, header.count()):
                header.setSectionHidden(sec, True)
    
        def sizeHint(self):
            baseSize = super(MyQTreeView,self).sizeHint()
    
            #---- get model index of "path" ----
            qindx = self.rootIndex().child(0, 0)
    
            if self.isExpanded(qindx): # default baseSize height will be used
                pass
    
            else:  # shrink baseShize height to the height of the row           
                baseSize.setHeight(self.rowHeight(qindx))
    
            return baseSize
    
    
    class MyQSortFilterProxyModel(QtGui.QSortFilterProxyModel):    
        def __init__(self, path, parent=None):
            super(MyQSortFilterProxyModel, self).__init__(parent)
    
            self.path = path
    
        def filterAcceptsRow(self, row, parent):
    
            model = self.sourceModel()
            path_dta = model.index(self.path).data()
            ppath_dta = model.index(os.path.dirname(self.path)).data()
    
            if parent.data() == ppath_dta:
                if parent.child(row, 0).data() == path_dta:                
                    return True
                else:
                    return False            
            else:
                return True
    

    2。如何将* QTreeView *添加到* QTableView *:

    可以使用 QItemDelegate QTreeView 添加到 QTableView post by wysota on Qt Centre对此有很大的帮助,因为我在回答这个问题之前从未将 QTableView 与代表结合使用。我总是使用 QTableWidget 而不是setCellWidget方法。

    请注意,我已在 MyDelegate 类中设置了一个信号,该类调用 MyTableView 类中的方法resizeRowsToContents。这样,行的高度根据 MyQTreeView 类的sizeHint方法的重新实现来调整大小。

    class MyTableModel(QtCore.QAbstractTableModel):
        def __init__(self, parent, mylist, header, *args):
            super(MyTableModel, self).__init__(parent, *args)
            self.mylist = mylist
            self.header = header
    
        def rowCount(self, parent=QtCore.QModelIndex()):
            return len(self.mylist)
    
        def columnCount(self, parent=QtCore.QModelIndex()):
            return len(self.mylist[0])
    
        def data(self, index, role):
            if not index.isValid():
                return None
            elif role != QtCore.Qt.DisplayRole:
                return None
            return self.mylist[index.row()][index.column()]
    
        def headerData(self, col, orientation, role):
            if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
                return self.header[col]
            return None
    
    class MyDelegate(QtGui.QItemDelegate):
    
        treeViewHeightChanged = QtCore.pyqtSignal(QtGui.QWidget)
    
        def createEditor(self, parent, option, index):
    
            editor = MyQTreeView(index.data(), parent)
            editor.collapsed.connect(self.sizeChanged)
            editor.expanded.connect(self.sizeChanged)
    
            return editor
    
        def sizeChanged(self):
            self.treeViewHeightChanged.emit(self.sender())
    
    class MyTableView(QtGui.QTableView):
        def __init__(self, data_list, header, *args):
            super(MyTableView, self).__init__(*args)
    
            #---- set up model ----
    
            model = MyTableModel(self, data_list, header)
            self.setModel(model)
    
            #---- set up delegate in last column ----
    
            delegate = MyDelegate()
    
            self.setItemDelegateForColumn(3, delegate)
            for row in range(model.rowCount()):
                self.openPersistentEditor(model.index(row, 3))
    
            #---- set up font and resize calls ----
    
            self.setFont(QtGui.QFont("Courier New", 14))
            self.resizeColumnsToContents()
            delegate.treeViewHeightChanged.connect(self.resizeRowsToContents)
    

    3。基本申请:

    以下是基于您在OP中提供的代码的基本应用程序:

    if __name__ == '__main__':
    
        header = ['Name', ' Email', ' Status', ' Path']
        data_list = [('option_A', 'zyro@email.com', 'Not Copied', '/opt'),
                     ('option_B', 'zyro@email.com', 'Not Copied', '/usr')]
    
        app = QtGui.QApplication([])
        win = MyTableView(data_list, header)
        win.setGeometry(300, 200, 570, 450)
        win.show()
        app.exec_()
    

    结果是:

    post by Pavel Strakhov