美文网首页Qt哒哒哒哒
PyQt5 系统化学习: 表格与树

PyQt5 系统化学习: 表格与树

作者: 水之心 | 来源:发表于2020-06-29 09:29 被阅读0次

    17 表格与树

    《PyQt5快速开发与实战》学习笔记。

    表格与树解决的问题是如何在一个控件中有规律地呈现更多的数据。PyQt5 提供了两种控件类用于解决该问题,其中一种是表格结构的控件类;另一种是树形结构的控件类。

    17.1 QTableView

    在通常情况下,一个应用需要和一批数据(比如数组、列表)进行交互,然后以表格的形式输出这些信息,这时就要用到 QTableView 类了。在 QtableView 中可以使用自定义的数据模型来显示内容,通过 setModel 来绑定数据源。

    QTableWidget 继承自 QTableView,主要区别是 QTableView 可以使用自定义的数据模型来显示内容(先要通过 setModel 来绑定数据源),而 QTableWidget 只能使用标准的数据模型,并且其单元格数据是通过QTableWidgetItem 对象来实现的。通常使用 QTableWidget 就能够满足我们的要求。

    QTableView 控件可以绑定一个模型数据用来更新控件上的内容,可用的模式如表所示。

    from PyQt5.QtWidgets import *
    from PyQt5.QtGui import *
    from PyQt5.QtCore import *
    import sys
    
    
    class Table(QWidget):
        def __init__(self, arg=None):
            super(Table, self).__init__(arg)
            self.setWindowTitle("QTableView表格视图控件的例子")
            self.resize(500, 300)
            self.model = QStandardItemModel(4, 4)
            self.model.setHorizontalHeaderLabels(['标题1', '标题2', '标题3', '标题4'])
    
            for row in range(4):
                for column in range(4):
                    item = QStandardItem("row %s, column %s" % (row, column))
                    self.model.setItem(row, column, item)
    
            self.tableView = QTableView()
            self.tableView.setModel(self.model)
            #下面代码让表格100填满窗口
            #self.tableView.horizontalHeader().setStretchLastSection(True)
            #self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
            dlgLayout = QVBoxLayout()
            dlgLayout.addWidget(self.tableView)
            self.setLayout(dlgLayout)
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        table = Table()
        table.show()
        sys.exit(app.exec_())
    

    效果:

    17.2 QListView

    QListView 类用于展示数据,它的子类是 QListWidget。QListView 是基于模型(Model)的,需要程序来建立模型,然后再保存数据。

    QListWidget 是一个升级版本的 QListView,它已经建立了一个数据存储模型(QListWidgetItem),直接调用addItem()函数,就可以添加条目(Item)。

    from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QListView, QMessageBox
    from PyQt5.QtCore import QStringListModel
    import sys
    
    
    class ListViewDemo(QWidget):
        def __init__(self, parent=None):
            super(ListViewDemo, self).__init__(parent)
            self.setWindowTitle("QListView 例子")
            self.resize(300, 270)
            layout = QVBoxLayout()
    
            listView = QListView()
            slm = QStringListModel()
            self.qList = ['Item 1', 'Item 2', 'Item 3', 'Item 4']
            slm.setStringList(self.qList)
            listView.setModel(slm)
            listView.clicked.connect(self.clicked)
            layout.addWidget(listView)
            self.setLayout(layout)
    
        def clicked(self, qModelIndex):
            QMessageBox.information(self, "QListView", "你选择了: " +
                                    self.qList[qModelIndex.row()])
    
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        win = ListViewDemo()
        win.show()
        sys.exit(app.exec_())
    

    效果:

    17.3 QListWidget

    QListWidet 类是一个基于条目的接口,用于从列表中添加或删除条目。列表中的每个条目都是一个QListWidgetItem 对象。QListWidget 可以设置为多重选择。

    import sys
    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    from PyQt5.QtWidgets import *
    
    
    class ListWidget(QListWidget):
        def clicked(self, item):
            QMessageBox.information(self, "ListWidget", "你选择了: "+item.text())
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        listWidget = ListWidget()
        listWidget.resize(300, 120)
        listWidget.addItem("Item 1")
        listWidget.addItem("Item 2")
        listWidget.addItem("Item 3")
        listWidget.addItem("Item 4")
        listWidget.setWindowTitle('QListwidget 例子')
        listWidget.itemClicked.connect(listWidget.clicked)
        listWidget.show()
        sys.exit(app.exec_())
    

    更复杂的例子:

    import sys
    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    from PyQt5.QtWidgets import *
    
    
    class StackedExample(QWidget):
        def __init__(self):
            super(StackedExample, self).__init__()
            self.setGeometry(300, 50, 10, 10)
            self.setWindowTitle('StackedWidget 例子')
    
            self.leftlist = QListWidget()
            self.leftlist.insertItem(0, '联系方式')
            self.leftlist.insertItem(1, '个人信息')
            self.leftlist.insertItem(2, '教育程度')
            self.stack1 = QWidget()
            self.stack2 = QWidget()
            self.stack3 = QWidget()
            self.stack1UI()
            self.stack2UI()
            self.stack3UI()
            self.Stack = QStackedWidget(self)
            self.Stack.addWidget(self.stack1)
            self.Stack.addWidget(self.stack2)
            self.Stack.addWidget(self.stack3)
            hbox = QHBoxLayout(self)
            hbox.addWidget(self.leftlist)
            hbox.addWidget(self.Stack)
            self.setLayout(hbox)
            self.leftlist.currentRowChanged.connect(self.display)
    
        def stack1UI(self):
            layout = QFormLayout()
            layout.addRow("姓名", QLineEdit())
            layout.addRow("地址", QLineEdit())
            self.stack1.setLayout(layout)
    
        def stack2UI(self):
            layout = QFormLayout()
            sex = QHBoxLayout()
            sex.addWidget(QRadioButton("男"))
            sex.addWidget(QRadioButton("女"))
            layout.addRow(QLabel("性别"), sex)
            layout.addRow("生日", QLineEdit())
            self.stack2.setLayout(layout)
    
        def stack3UI(self):
            layout = QHBoxLayout()
            layout.addWidget(QLabel("科目"))
            layout.addWidget(QCheckBox("物理"))
            layout.addWidget(QCheckBox("高数"))
            self.stack3.setLayout(layout)
    
        def display(self, i):
            self.Stack.setCurrentIndex(i)
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        demo = StackedExample()
        demo.show()
        sys.exit(app.exec_())
    

    17.4 QTableWidget

    QTableWidget 是 Qt 程序中常用的显示数据表格的空间,类似于 C# 中的 DataGrid。QTableWidget 是QTableView 的子类,它使用标准的数据模型,并且其单元格数据是通过 QTableWidgetItem 对象来实现的。使用 QTableWidget 时就需要 QTableWidgetItem,用来表示表格中的一个单元格,整个表格就是用各单元格构建起来的。

    QTableWidget类中的常用方法如表:

    如果要设置水平和垂直对齐方式,比如在表格空间内上下、左右居中对齐,那么只要使用 Qt.AlignHCenter 和Qt.AlignVCenter 即可。

    17.4.1 基本用法

    本例主要介绍基本表格的用法。在表格控件中显示的数据是可编辑的。在 QTableWidget 表格中具体单元格就是 QTableWidgetItem 类。其完整代码如下:

    import sys
    from PyQt5.QtWidgets import (
        QWidget, QTableWidget, QHBoxLayout, QApplication, QTableWidgetItem, QAbstractItemView)
    
    
    class Table(QWidget):
        def __init__(self):
            super().__init__()
            self.initUI()
    
        def initUI(self):
            self.setWindowTitle("QTableWidget 例子")
            self.resize(430, 230)
            conLayout = QHBoxLayout()
            tableWidget = QTableWidget()
            tableWidget.setRowCount(4)
            tableWidget.setColumnCount(3)
            conLayout.addWidget(tableWidget)
    
            tableWidget.setHorizontalHeaderLabels(['姓名', '性别', '体重(kg)'])
    
            newItem = QTableWidgetItem("张三")
            tableWidget.setItem(0, 0, newItem)
    
            newItem = QTableWidgetItem("男")
            tableWidget.setItem(0, 1, newItem)
    
            newItem = QTableWidgetItem("160")
            tableWidget.setItem(0, 2, newItem)
    
            # 将表格变为禁止编辑
            #tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
    
            # 设置表格为整行选择
            #tableWidget.setSelectionBehavior( QAbstractItemView.SelectRows)
    
            # 将行和列的大小设为与内容相匹配
            #tableWidget.resizeColumnsToContents()
            #tableWidget.resizeRowsToContents()
    
            #表格表头的显示与隐藏
            #tableWidget.verticalHeader().setVisible(False)
            #tableWidget.horizontalHeader().setVisible(False)
    
            # 不显示表格单元格的分割线
            #tableWidget.setShowGrid(False)
            # 不显示垂直表头
            tableWidget.verticalHeader().setVisible(False)
    
            self.setLayout(conLayout)
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        example = Table()
        example.show()
        sys.exit(app.exec_())
    

    效果:

    import sys
    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    from PyQt5.QtWidgets import *
              
    class TabDemo(QTabWidget):
        def __init__(self, parent=None):
            super(TabDemo, self).__init__(parent)   
            self.tab1 = QWidget()
            self.tab2 = QWidget()
            self.tab3 = QWidget()
            self.addTab(self.tab1,"Tab 1")
            self.addTab(self.tab2,"Tab 2")
            self.addTab(self.tab3,"Tab 3")
            self.tab1UI()
            self.tab2UI()
            self.tab3UI()
            self.setWindowTitle("Tab 例子")
            
        def tab1UI(self):
            layout = QFormLayout()
            layout.addRow("姓名",QLineEdit())
            layout.addRow("地址",QLineEdit())
            self.setTabText(0,"联系方式")
            self.tab1.setLayout(layout)
            
        def tab2UI(self):
            layout = QFormLayout()
            sex = QHBoxLayout()
            sex.addWidget(QRadioButton("男"))    
            sex.addWidget(QRadioButton("女"))
            layout.addRow(QLabel("性别"),sex)
            layout.addRow("生日",QLineEdit())
            self.setTabText(1,"个人详细信息")
            self.tab2.setLayout(layout)
            
        def tab3UI(self):
            layout=QHBoxLayout()
            layout.addWidget(QLabel("科目"))
            layout.addWidget(QCheckBox("物理"))
            layout.addWidget(QCheckBox("高数"))
            self.setTabText(2,"教育程度")
            self.tab3.setLayout(layout)
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        demo = TabDemo()
        demo.show()
        sys.exit(app.exec_())
    

    效果:

    17.4.2 在表格中快速定位到指定行

    当 tableWidget 表格的行数很多时,可以通过输入行号进行直接定位并显示,比如输入 10,就直接显示第 10行:

    import sys
    from PyQt5.QtWidgets import *
    from PyQt5 import QtCore
    from PyQt5.QtGui import QColor, QBrush
    
    
    class Table(QWidget):
        def __init__(self):
            super().__init__()
            self.initUI()
    
        def initUI(self):
            self.setWindowTitle("QTableWidget 例子")
            self.resize(600, 800)
            conLayout = QHBoxLayout()
            tableWidget = QTableWidget()
            tableWidget.setRowCount(30)
            tableWidget.setColumnCount(4)
            conLayout.addWidget(tableWidget)
    
            for i in range(30):
                for j in range(4):
                    itemContent = '(%d,%d)' % (i, j)
                    tableWidget.setItem(i, j, QTableWidgetItem(itemContent))
            self.setLayout(conLayout)
    
            #遍历表查找对应的item
            text = "(10,1)"
            items = tableWidget.findItems(text, QtCore.Qt.MatchExactly)
            item = items[0]
            # 选中单元格
            #item.setSelected( True)
            # 设置单元格的背景颜色为红色
            item.setForeground(QBrush(QColor(255, 0, 0)))
    
            row = item.row()
            #滚轮定位过去,快速定位到第17行
            tableWidget.verticalScrollBar().setSliderPosition(row)
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        example = Table()
        example.show()
        sys.exit(app.exec_())
    

    效果:

    17.4.3 设置单元格文本颜色

    将表格第一行中三个单元格的文本颜色设置为红色:

    import sys
    from PyQt5.QtWidgets import (
        QWidget, QTableWidget, QHBoxLayout, QApplication, QTableWidgetItem)
    from PyQt5.QtGui import QBrush,  QColor,  QFont
    
    
    class Table(QWidget):
        def __init__(self):
            super().__init__()
            self.initUI()
    
        def initUI(self):
            self.setWindowTitle("QTableWidget 例子")
            self.resize(430, 230)
            conLayout = QHBoxLayout()
            tableWidget = QTableWidget()
            tableWidget.setRowCount(4)
            tableWidget.setColumnCount(3)
            conLayout.addWidget(tableWidget)
    
            tableWidget.setHorizontalHeaderLabels(['姓名', '性别', '体重(kg)'])
    
            newItem = QTableWidgetItem("张三")
            newItem.setForeground(QBrush(QColor(255, 0, 0)))
            tableWidget.setItem(0, 0, newItem)
    
            newItem = QTableWidgetItem("男")
            newItem.setForeground(QBrush(QColor(255, 0, 0)))
            tableWidget.setItem(0, 1, newItem)
    
            newItem = QTableWidgetItem("160")
            newItem.setForeground(QBrush(QColor(255, 0, 0)))
            tableWidget.setItem(0, 2, newItem)
    
            self.setLayout(conLayout)
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        example = Table()
        example.show()
        sys.exit(app.exec_())
    

    效果:

    17.4.4 将字体加粗

    import sys
    from PyQt5.QtWidgets import (
        QWidget, QTableWidget, QHBoxLayout, QApplication, QTableWidgetItem)
    from PyQt5.QtGui import QBrush,  QColor,  QFont
    
    
    class Table(QWidget):
        def __init__(self):
            super().__init__()
            self.initUI()
    
        def initUI(self):
            self.setWindowTitle("QTableWidget 例子")
            self.resize(430, 230)
            conLayout = QHBoxLayout()
            tableWidget = QTableWidget()
            tableWidget.setRowCount(4)
            tableWidget.setColumnCount(3)
            conLayout.addWidget(tableWidget)
    
            tableWidget.setHorizontalHeaderLabels(['姓名', '性别', '体重(kg)'])
    
            newItem = QTableWidgetItem("张三")
            newItem.setFont(QFont("Times", 12, QFont.Black))
            tableWidget.setItem(0, 0, newItem)
    
            newItem = QTableWidgetItem("男")
            newItem.setFont(QFont("Times", 12, QFont.Black))
            tableWidget.setItem(0, 1, newItem)
    
            newItem = QTableWidgetItem("160")
            newItem.setFont(QFont("Times", 12, QFont.Black))
            tableWidget.setItem(0, 2, newItem)
    
            self.setLayout(conLayout)
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        example = Table()
        example.show()
        sys.exit(app.exec_())
    

    效果:

    17.4.5 设置单元格的排序方式

    查看 Qt 的开发文档(https://doc.qt.io/qt-5/qt.xhtml#details),可以看到使用 Qt.DescendingOrder 表示在单元格内降序排列,使用 Qt.AscendingOrder 表示在单元格内升序排列。但是需要使用以下语句从PyQt5.QtCore 模块导入 Qt 类。

    from PyQt5.QtCore import Qt 
    

    演示在表格中按照体重进行降序排列显示,其代码如下:

    # Qt.DescendingOrder 降序 
    # Qt.AscendingOrder 升序 
    # -*- coding: utf-8 -*-
    import sys
    from PyQt5.QtWidgets import (
        QWidget, QTableWidget, QHBoxLayout, QApplication, QTableWidgetItem)
    from PyQt5.QtCore import Qt
    
    
    class Table(QWidget):
        def __init__(self):
            super().__init__()
            self.initUI()
    
        def initUI(self):
            self.setWindowTitle("QTableWidget 例子")
            self.resize(430, 230)
            conLayout = QHBoxLayout()
            tableWidget = QTableWidget()
            tableWidget.setRowCount(4)
            tableWidget.setColumnCount(3)
            conLayout.addWidget(tableWidget)
    
            tableWidget.setHorizontalHeaderLabels(['姓名', '性别', '体重(kg)'])
    
            newItem = QTableWidgetItem("张三")
            tableWidget.setItem(0, 0, newItem)
    
            newItem = QTableWidgetItem("男")
            tableWidget.setItem(0, 1, newItem)
    
            newItem = QTableWidgetItem("160")
            tableWidget.setItem(0, 2, newItem)
    
            newItem = QTableWidgetItem("李四")
            tableWidget.setItem(1, 0, newItem)
    
            newItem = QTableWidgetItem("女")
            tableWidget.setItem(1, 1, newItem)
    
            newItem = QTableWidgetItem("155")
            tableWidget.setItem(1, 2, newItem)
    
            newItem = QTableWidgetItem("王五")
            tableWidget.setItem(2, 0, newItem)
    
            newItem = QTableWidgetItem("男")
            tableWidget.setItem(2, 1, newItem)
    
            newItem = QTableWidgetItem("170")
            tableWidget.setItem(2, 2, newItem)
    
            # Qt.DescendingOrder 降序
            # Qt.AscendingOrder 升序
            tableWidget.sortItems(2,  Qt.DescendingOrder)
    
            self.setLayout(conLayout)
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        example = Table()
        example.show()
        sys.exit(app.exec_())
    

    效果:

    17.4.6 设置单元格文本的对齐方式

    使用 QTableWidgetItem.setTextAlignment(int) 函数设置单元格文本的对齐方式,该函数的参数为对齐方式。

    查看Qt的开发文档(https://doc.qt.io/qt-5/qt.xhtml#details),可以看到水平和垂直方向上的对齐方式。Qt 的文本对齐方式同样也可以应用在 PyQt5 中。

    演示第一行第一列的单元格内容右对齐并与底部对齐。其代码如下:

    import sys
    from PyQt5.QtWidgets import (
        QWidget, QTableWidget, QHBoxLayout, QApplication, QTableWidgetItem)
    from PyQt5.QtCore import Qt
    
    
    class Table(QWidget):
        def __init__(self):
            super().__init__()
            self.initUI()
    
        def initUI(self):
            self.setWindowTitle("QTableWidget 例子")
            self.resize(430, 230)
            conLayout = QHBoxLayout()
            tableWidget = QTableWidget()
            tableWidget.setRowCount(4)
            tableWidget.setColumnCount(3)
            conLayout.addWidget(tableWidget)
    
            tableWidget.setHorizontalHeaderLabels(['姓名', '性别', '体重(kg)'])
            newItem = QTableWidgetItem("张三")
    
            newItem.setTextAlignment(Qt.AlignRight | Qt.AlignBottom)
            tableWidget.setItem(0, 0, newItem)
    
            newItem = QTableWidgetItem("男")
            tableWidget.setItem(0, 1, newItem)
    
            newItem = QTableWidgetItem("160")
            tableWidget.setItem(0, 2, newItem)
    
            self.setLayout(conLayout)
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        example = Table()
        example.show()
        sys.exit(app.exec_())
    

    效果:

    17.4.7 合并单元格效果的实现

    比如,将表格中第一行第一列的单元格,更改为占据 3 行 1 列。代码如下:

    # -*- coding: utf-8 -*-
    import sys
    from PyQt5.QtWidgets import (
        QWidget, QTableWidget, QHBoxLayout, QApplication, QTableWidgetItem)
    
    
    class Table(QWidget):
        def __init__(self):
            super().__init__()
            self.initUI()
    
        def initUI(self):
            self.setWindowTitle("QTableWidget 例子")
            self.resize(430, 230)
            conLayout = QHBoxLayout()
            tableWidget = QTableWidget()
            tableWidget.setRowCount(4)
            tableWidget.setColumnCount(3)
            conLayout.addWidget(tableWidget)
    
            tableWidget.setHorizontalHeaderLabels(['姓名', '性别', '体重(kg)'])
            tableWidget.setSpan(0, 0, 3, 1)
    
            newItem = QTableWidgetItem("张三")
            tableWidget.setItem(0, 0, newItem)
    
            newItem = QTableWidgetItem("男")
            tableWidget.setItem(0, 1, newItem)
    
            newItem = QTableWidgetItem("160")
            tableWidget.setItem(0, 2, newItem)
    
            self.setLayout(conLayout)
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        example = Table()
        example.show()
        sys.exit(app.exec_())
    

    效果:

    17.4.8 设置单元格的大小

    演示将第一列的单元格宽度设置为 150,将第一行的单元格高度设置为120:

    import sys
    from PyQt5.QtWidgets import (
        QWidget, QTableWidget, QHBoxLayout, QApplication, QTableWidgetItem)
    
    
    class Table(QWidget):
        def __init__(self):
            super().__init__()
            self.initUI()
    
        def initUI(self):
            self.setWindowTitle("QTableWidget 例子")
            self.resize(530, 300)
            conLayout = QHBoxLayout()
            tableWidget = QTableWidget()
            tableWidget.setRowCount(4)
            tableWidget.setColumnCount(3)
            conLayout.addWidget(tableWidget)
    
            tableWidget.setHorizontalHeaderLabels(['姓名', '性别', '体重(kg)'])
    
            newItem = QTableWidgetItem("张三")
            tableWidget.setItem(0, 0, newItem)
    
            #将第1列的单元格,设置成150宽度
            tableWidget.setColumnWidth(0, 150)
            #将第1行的单元格,设置成120的高度
            tableWidget.setRowHeight(0, 120)
    
            newItem = QTableWidgetItem("男")
            tableWidget.setItem(0, 1, newItem)
    
            newItem = QTableWidgetItem("160")
            tableWidget.setItem(0, 2, newItem)
    
            self.setLayout(conLayout)
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        example = Table()
        example.show()
        sys.exit(app.exec_())
    

    效果如下:

    17.4.9 在表格中不显示分割线

    QTableWidget 类的 setShowGrid()函数是从 QTableView 类继承的,用来设置是否显示表格的分割线,默认显示分割线。使用以下代码,则不显示分割线。

    17.4.10 为单元格添加图片

    还可以在单元格内添加图片,并显示图片的描述信息。

    import sys
    from PyQt5.QtWidgets import *
    from PyQt5.QtGui import *
    from PyQt5.QtCore import *
    
    
    class Table(QWidget):
    
        def __init__(self):
            super().__init__()
            self.initUI()
    
        def initUI(self):
            self.setWindowTitle("QTableWidget 例子")
            self.resize(500, 300)
            conLayout = QHBoxLayout()
            self.tableWidget = QTableWidget()
            self.tableWidget.setRowCount(5)
            self.tableWidget.setColumnCount(4)
            conLayout.addWidget(self.tableWidget)
    
            self.tableWidget.setHorizontalHeaderLabels(['姓名', '性别', '体重', '显示图片'])
            self.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
    
            newItem = QTableWidgetItem("张三")
            self.tableWidget.setItem(0, 0, newItem)
    
            newItem = QTableWidgetItem("男")
            self.tableWidget.setItem(0, 1, newItem)
    
            newItem = QTableWidgetItem("160")
            self.tableWidget.setItem(0, 2, newItem)
    
            newItem = QTableWidgetItem(QIcon("./images/bao1.png"), "背包")
            self.tableWidget.setItem(0, 3, newItem)
            self.setLayout(conLayout)
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        example = Table()
        example.show()
        sys.exit(app.exec_())
    

    效果如下:

    17.4.11 改变单元格中显示的图片大小

    使用 QTableWidget 默认处理 QTableWidgetItem 对象,在每个单元格中放置图片。

    import sys
    from PyQt5.QtWidgets import *
    from PyQt5.QtGui import *
    from PyQt5.QtCore import *
    
    
    class Table(QWidget):
        def __init__(self):
            super().__init__()
            self.initUI()
    
        def initUI(self):
            self.setWindowTitle("QTableWidget 例子")
            self.resize(1000, 900)
            conLayout = QHBoxLayout()
    
            table = QTableWidget()
            table.setColumnCount(3)
            table.setRowCount(5)
    
            table.setHorizontalHeaderLabels(['图片1', '图片2', '图片3'])
    
            table.setEditTriggers(QAbstractItemView.NoEditTriggers)
    
            table.setIconSize(QSize(300, 200))
    
            for i in range(3):   # 让列宽和图片相同
               table.setColumnWidth(i, 300)
            for i in range(5):   # 让行高和图片相同
                table.setRowHeight(i, 200)
    
            for k in range(15):  # 27 examples of DDA
                i = k/3
                j = k % 3
                item = QTableWidgetItem()
                item.setFlags(Qt.ItemIsEnabled)  # 用户点击时表格时,图片被选中
                icon = QIcon(r'.\images\bao%d.png' % k)
                item.setIcon(QIcon(icon))
    
                print('e/icons/%d.png i=%d  j=%d' % (k, i, j))
                table.setItem(i, j, item)
    
            conLayout.addWidget(table)
            self.setLayout(conLayout)
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        example = Table()
        example.show()
        sys.exit(app.exec_())
    

    效果如下:

    17.4.12 获得单元格的内容

    通过实现 itemClicked (QTableWidgetItem *) 信号的 slot 函数,可以获得所点击的单元格的引用,进而获得其中的内容。以下代码将 itemClicked 信号与 getItem() 函数进行绑定:

    tableWidget.itemClicked.connect( self.handleItemClick ) 
    def getItem(self,item): 
    print('you selected=﹥ '+ item.text()) 
    

    17.4.13 支持右键菜单

    选中某个单元格后,单击鼠标右键,从弹出的快捷菜单:

    import sys
    from PyQt5.QtWidgets import (QMenu, QPushButton,  QWidget, QTableWidget,
                                 QHBoxLayout, QApplication, QTableWidgetItem, QHeaderView)
    from PyQt5.QtCore import QObject, Qt
    
    
    class Table(QWidget):
        def __init__(self):
            super().__init__()
            self.initUI()
    
        def initUI(self):
            self.setWindowTitle("QTableWidget 例子")
            self.resize(500, 300)
            conLayout = QHBoxLayout()
            self.tableWidget = QTableWidget()
            self.tableWidget.setRowCount(5)
            self.tableWidget.setColumnCount(3)
            conLayout.addWidget(self.tableWidget)
    
            self.tableWidget.setHorizontalHeaderLabels(['姓名', '性别', '体重'])
            self.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
    
            newItem = QTableWidgetItem("张三")
            self.tableWidget.setItem(0, 0, newItem)
    
            newItem = QTableWidgetItem("男")
            self.tableWidget.setItem(0, 1, newItem)
    
            newItem = QTableWidgetItem("160")
            self.tableWidget.setItem(0, 2, newItem)
            #表格中第二行记录
            newItem = QTableWidgetItem("李四")
            self.tableWidget.setItem(1, 0, newItem)
    
            newItem = QTableWidgetItem("女")
            self.tableWidget.setItem(1, 1, newItem)
    
            newItem = QTableWidgetItem("170")
            self.tableWidget.setItem(1, 2, newItem)
    
            self.tableWidget.setContextMenuPolicy(Qt.CustomContextMenu)  # 允许右键产生子菜单
            self.tableWidget.customContextMenuRequested.connect(
                self.generateMenu)  # 右键菜单
            self.setLayout(conLayout)
    
        def generateMenu(self, pos):
            #rint( pos)
            row_num = -1
            for i in self.tableWidget.selectionModel().selection().indexes():
                row_num = i.row()
    
            if row_num < 2:
                menu = QMenu()
                item1 = menu.addAction(u"选项一")
                item2 = menu.addAction(u"选项二")
                item3 = menu.addAction(u"选项三")
                action = menu.exec_(self.tableWidget.mapToGlobal(pos))
                if action == item1:
                    print('您选了选项一,当前行文字内容是:', self.tableWidget.item(row_num, 0).text(
                    ), self.tableWidget.item(row_num, 1).text(), self.tableWidget.item(row_num, 2).text())
    
                elif action == item2:
                    print('您选了选项二,当前行文字内容是:', self.tableWidget.item(row_num, 0).text(
                    ), self.tableWidget.item(row_num, 1).text(), self.tableWidget.item(row_num, 2).text())
    
                elif action == item3:
                    print('您选了选项三,当前行文字内容是:', self.tableWidget.item(row_num, 0).text(
                    ), self.tableWidget.item(row_num, 1).text(), self.tableWidget.item(row_num, 2).text())
                else:
                    return
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        example = Table()
        example.show()
        sys.exit(app.exec_())
    

    效果:

    17.5 QTreeView

    QTreeWidget类实现了树形结构。

    17.5.1 树形结构的实现

    树形结构是通过 QTreeWidget 和 QTreeWidgetItem 类实现的,其中 QTreeWidgetItem 类实现了节点的添加。

    import sys
    from PyQt5.QtWidgets import *
    from PyQt5.QtGui import QIcon,  QBrush, QColor
    from PyQt5.QtCore import Qt
    
    
    class TreeWidgetDemo(QMainWindow):
        def __init__(self, parent=None):
            super(TreeWidgetDemo, self).__init__(parent)
            self.setWindowTitle('TreeWidget 例子')
            self.tree = QTreeWidget()
            # 设置列数
            self.tree.setColumnCount(2)
            # 设置头的标题
            self.tree.setHeaderLabels(['Key', 'Value'])
            # 设置根节点
            root = QTreeWidgetItem(self.tree)
            root.setText(0, 'root')
            root.setIcon(0, QIcon("./images/root.png"))
            # 设置列宽
            self.tree.setColumnWidth(0, 160)
    
            ### 设置节点的背景颜色
            #brush_red = QBrush(Qt.red)
            #root.setBackground(0, brush_red)
            #brush_green = QBrush(Qt.green)
            #root.setBackground(1, brush_green)
    
            # 设置子节点1
            child1 = QTreeWidgetItem(root)
            child1.setText(0, 'child1')
            child1.setText(1, 'ios')
            child1.setIcon(0, QIcon("./images/IOS.png"))
            child1.setCheckState(0, Qt.Checked)
    
            # 设置子节点2
            child2 = QTreeWidgetItem(root)
            child2.setText(0, 'child2')
            child2.setText(1, '')
            child2.setIcon(0, QIcon("./images/android.png"))
    
            # 设置子节点3
            child3 = QTreeWidgetItem(child2)
            child3.setText(0, 'child3')
            child3.setText(1, 'android')
            child3.setIcon(0, QIcon("./images/music.png"))
    
            self.tree.addTopLevelItem(root)
            # 结点全部展开
            self.tree.expandAll()
    
            self.setCentralWidget(self.tree)
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        tree = TreeWidgetDemo()
        tree.show()
        sys.exit(app.exec_())
    

    效果:

    17.5.2 给节点添加响应事件

    演示当单击树形控件时,触发树形控件节点的响应事件。其完整代码如下:

    from PyQt5.QtWidgets import *
    import sys
    
    
    class TreeWidgetDemo(QMainWindow):
        def __init__(self, parent=None):
            super(TreeWidgetDemo, self).__init__(parent)
            self.setWindowTitle('TreeWidget 例子')
            self.tree = QTreeWidget()
            # 设置列数
            self.tree.setColumnCount(2)
            # 设置头的标题
            self.tree.setHeaderLabels(['Key', 'Value'])
            root = QTreeWidgetItem(self.tree)
            root.setText(0, 'root')
            root.setText(1, '0')
    
            child1 = QTreeWidgetItem(root)
            child1.setText(0, 'child1')
            child1.setText(1, '1')
    
            child2 = QTreeWidgetItem(root)
            child2.setText(0, 'child2')
            child2.setText(1, '2')
    
            child3 = QTreeWidgetItem(root)
            child3.setText(0, 'child3')
            child3.setText(1, '3')
    
            child4 = QTreeWidgetItem(child3)
            child4.setText(0, 'child4')
            child4.setText(1, '4')
    
            child5 = QTreeWidgetItem(child3)
            child5.setText(0, 'child5')
            child5.setText(1, '5')
    
            self.tree.addTopLevelItem(root)
            self.tree.clicked.connect(self.onTreeClicked)
    
            self.setCentralWidget(self.tree)
    
        def onTreeClicked(self, qmodelindex):
            item = self.tree.currentItem()
            print("key=%s ,value=%s" % (item.text(0), item.text(1)))
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        tree = TreeWidgetDemo()
        tree.show()
        sys.exit(app.exec_())
    

    效果如下:

    17.5.3 系统定制模式

    在上面的例子中,QTreeWidgetItem 类的节点是一个个添加的,这样做有时很不方便,特别是当窗口中产生比较复杂的树形结构时,一般都是通过 QTreeView 类来实现的,而不是 QTreeWidget 类。QTreeView 类与 QTreeWidget 类最大的区别就是,QTreeView 类可以使用操作系统提供的定制模式,比如文件系统盘的树列表。

    import sys
    from PyQt5.QtWidgets import *
    from PyQt5.QtGui import *
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        #Window系统提供的模式
        model = QDirModel()
        #创建一个QtreeView部件
        tree = QTreeView()
        #为部件添加模式
        tree.setModel(model)
        tree.setWindowTitle("QTreeView 例子")
        tree.resize(640, 480)
        tree.show()
        sys.exit(app.exec_())
    

    效果如下:

    相关文章

      网友评论

        本文标题:PyQt5 系统化学习: 表格与树

        本文链接:https://www.haomeiwen.com/subject/lgonfktx.html