前言

首先为上周的博文鸽掉而毫无诚意地道个歉,汪汪。上周的文章先记在账上,之后慢慢补。

因为工作和生活的变动,移居到了另一个城市,各种辛苦就不说了,目前总算是告一段落,也算是个新的开始,加油。

今天继续来说一下PyQt的常用控件之QTreeWidget和QTreeView,两者的区别与QList相同就不赘述了,直接到使用环节。

QTree控件有可以有多层嵌套,经常会用在有层级或者父子关系的数据展示中,例如文件路径、部门层级、省市地区等等。

 

QTreeWidget

QTreeWidget的使用很简单,代码如下:

from Qt import QtCore, QtWidgets, QtGui
from Qt.QtCompat import load_ui, QFileDialog


class testPanel(QtWidgets.QWidget):

    def __init__(self):
        super(testPanel, self).__init__()
        DIR, file_name = os.path.split(os.path.abspath(__file__))
        load_ui(os.path.join(DIR, "QTreeWidget.ui"), self)

        self.initUI()

        self.bindEvent()

    def initUI(self):
        self.treeWidget.setColumnCount(2)
        self.treeWidget.setColumnWidth(0,400)
        self.treeWidget.setHeaderLabels(["name", "msg"])


    def bindEvent(self):
        self.pushButton_1.clicked.connect(self.add)
        self.pushButton_2.clicked.connect(self.remove)
        self.treeWidget.clicked.connect(self.click)

    # add Item
    def add(self):
        root = QtWidgets.QTreeWidgetItem()
        root.setText(0, "zhangsan")
        root.setIcon(0, QtGui.QIcon("./logo.png"))
        root.setCheckState(0, QtCore.Qt.Checked)
        child1 = QtWidgets.QTreeWidgetItem()
        child1.setText(0, "zhangsan1")
        child1.setIcon(0, QtGui.QIcon("./logo.png"))
        child1.setCheckState(0, QtCore.Qt.Checked)
        root.addChild(child1)
        child2 = QtWidgets.QTreeWidgetItem()
        child2.setText(0, "zhangsan2")
        child2.setText(1, "法外狂徒")
        child2.setIcon(0, QtGui.QIcon("./logo.png"))
        child2.setCheckState(0, QtCore.Qt.Checked)
        child1.addChild(child2)
        self.treeWidget.addTopLevelItem(root)

    # remove item
    def remove(self):
        item = self.treeWidget.currentItem()
        parent = item.parent()
        if not parent:
            rootIndex = self.treeWidget.indexOfTopLevelItem(item)
            self.treeWidget.takeTopLevelItem(rootIndex)
        else:
            parent.removeChild(item)

    # Item Clicked
    def click(self):
        item = self.treeWidget.currentItem()
        self.label.setText("key=%s,value=%s"%(item.text(0),item.text(1)))
		
app = QtWidgets.QApplication(sys.argv)
mt = testPanel()
mt.show()
app.exec_()

效果如下:

如上图,层级之间为包含关系,有复选框及图标,可以方便地添加和删除以及获取数据。

常用的样式表如下:

QTreeWidget {background-color:#2b2b2b;}
QTreeWidget::item:selected,QTreeWidget::item:hover {background-color:#fa8c16;border: none;}
QHeaderView::section {background-color: #5d5d5d;}
QTreeWidget::branch {color: #bbbbbb; }

 

QTreeView

接下来就要说一说前文中提到的QDirModel,不过实际使用中更多的会用到QFileSystemModel,相比起来,后者的优点是异步处理,在处理大量数据时不会造成UI阻塞。

示例代码如下:

from Qt import QtCore, QtWidgets, QtGui
from Qt.QtCompat import load_ui, QFileDialog

class testPanel(QtWidgets.QWidget):

    def __init__(self):
        super(testPanel, self).__init__()
        DIR, file_name = os.path.split(os.path.abspath(__file__))
        load_ui(os.path.join(DIR, "QTreeView.ui"), self)

        self.initUI()

        self.bindEvent()

    def initUI(self):
        self.model = QtWidgets.QFileSystemModel()  # QtWidgets.QDirModel
        dirpath = "C:/Anaconda3"
        self.model.setRootPath(dirpath)
        self.model.setNameFilters(["*.py"])
        self.model.setNameFilterDisables(False)

        self.treeView.setModel(self.model)
        self.treeView.setRootIndex(self.model.index(dirpath))
        self.treeView.setColumnWidth(0, 400)

    def bindEvent(self):
        self.treeView.clicked.connect(self.click)

    # Item Clicked
    def click(self,QModelIndex):
        self.label.setText("path=%s,name=%s,size=%s"%(self.model.filePath(QModelIndex),self.model.fileName(QModelIndex),self.model.fileInfo(QModelIndex).size()))


app = QtWidgets.QApplication(sys.argv)
mt = testPanel()
mt.show()
app.exec_()

效果如下:

这就是一个常用的文件浏览器的界面。

QTreeView的常用样式如下:

QTreeView {background-color:#2b2b2b;}
QTreeView::item:selected,QTreeView::item:hover {background-color:#fa8c16;border: none;}
QHeaderView::section {background-color: #5d5d5d;}
QTreeView::branch {color: #bbbbbb; }

如果要用QTreeView实现上面QTreeWidget呢,当然也可以通过QStandardItemModel轻松地实现,代码如下:

from Qt import QtCore, QtWidgets, QtGui
from Qt.QtCompat import load_ui, QFileDialog

class testPanel(QtWidgets.QWidget):

    def __init__(self):
        super(testPanel, self).__init__()
        DIR, file_name = os.path.split(os.path.abspath(__file__))
        load_ui(os.path.join(DIR, "QTreeView.ui"), self)

        self.initUI()

        self.bindEvent()

    def initUI(self):
        self.model = QtGui.QStandardItemModel()
        self.treeView.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)

        self.treeView.setModel(self.model)
        self.model.setHorizontalHeaderLabels(["name", "msg"])
        self.model.setColumnCount(2)
        self.treeView.setAutoScroll(True)
        self.treeView.setColumnWidth(0, 400)

    def bindEvent(self):
        self.pushButton_1.clicked.connect(self.add)
        self.pushButton_2.clicked.connect(self.remove)
        self.treeView.selectionModel().selectionChanged.connect(self.selectionChanged)

    # add Item
    def add(self):
        icon = QtGui.QIcon('./logo.png')

        item1 = QtGui.QStandardItem(icon, "zhangsan1")
        item1.setCheckState(QtCore.Qt.Checked)
        self.model.appendRow([item1])

        item2 = QtGui.QStandardItem(icon, "zhangsan2")
        item2.setCheckState(QtCore.Qt.Checked)
        item1.appendRow([item2])

        item3 = QtGui.QStandardItem(icon, "zhangsan3")
        item3.setCheckState(QtCore.Qt.Checked)

        item3_1 = QtGui.QStandardItem("法外狂徒")
        item2.appendRow([item3,item3_1])

        self.model.sort(0)

    # remove item
    def remove(self):
        index = self.treeView.currentIndex()
        if index:
            self.model.removeRow(index.row(), index.parent())


    # Item Change
    def selectionChanged(self,QModelIndex):
        indexs = self.treeView.selectedIndexes()

        if indexs:
            item = self.model.itemFromIndex(indexs[0])
            self.label.setText("name=%s,msg=%s"%(item.text(),indexs[0].sibling(indexs[0].row(), 1).data()))

app = QtWidgets.QApplication(sys.argv)
mt = testPanel()
mt.show()
app.exec_()

效果如下:

这些都是比较基础的用法,但长时间不用总是难免生疏,查找资料也比较费劲,故整理出来,留作笔记。

 


没有被听见,
不是沉默的理由。

《悲惨世界》
——维克多·雨果