PyQt5|PyQt5 系统化学习: 表格与树

17 表格与树 《PyQt5快速开发与实战》学习笔记。
表格与树解决的问题是如何在一个控件中有规律地呈现更多的数据。PyQt5 提供了两种控件类用于解决该问题,其中一种是表格结构的控件类;另一种是树形结构的控件类。
17.1 QTableView
在通常情况下,一个应用需要和一批数据(比如数组、列表)进行交互,然后以表格的形式输出这些信息,这时就要用到 QTableView 类了。在 QtableView 中可以使用自定义的数据模型来显示内容,通过 setModel 来绑定数据源。
QTableWidget 继承自 QTableView,主要区别是 QTableView 可以使用自定义的数据模型来显示内容(先要通过 setModel 来绑定数据源),而 QTableWidget 只能使用标准的数据模型,并且其单元格数据是通过QTableWidgetItem 对象来实现的。通常使用 QTableWidget 就能够满足我们的要求。
QTableView 控件可以绑定一个模型数据用来更新控件上的内容,可用的模式如表所示。
PyQt5|PyQt5 系统化学习: 表格与树
文章图片

from PyQt5.QtWidgets import * from PyQt5.QtGui import * from PyQt5.QtCore import * import sysclass 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_())

效果:
PyQt5|PyQt5 系统化学习: 表格与树
文章图片
17.2 QListView
QListView 类用于展示数据,它的子类是 QListWidget。QListView 是基于模型(Model)的,需要程序来建立模型,然后再保存数据。
QListWidget 是一个升级版本的 QListView,它已经建立了一个数据存储模型(QListWidgetItem),直接调用addItem()函数,就可以添加条目(Item)。
PyQt5|PyQt5 系统化学习: 表格与树
文章图片
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QListView, QMessageBox from PyQt5.QtCore import QStringListModel import sysclass 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_())

效果:
PyQt5|PyQt5 系统化学习: 表格与树
文章图片
17.3 QListWidget
QListWidet 类是一个基于条目的接口,用于从列表中添加或删除条目。列表中的每个条目都是一个QListWidgetItem 对象。QListWidget 可以设置为多重选择。
PyQt5|PyQt5 系统化学习: 表格与树
文章图片
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_())

PyQt5|PyQt5 系统化学习: 表格与树
文章图片
17.4 QTableWidget
QTableWidget 是 Qt 程序中常用的显示数据表格的空间,类似于 C# 中的 DataGrid。QTableWidget 是QTableView 的子类,它使用标准的数据模型,并且其单元格数据是通过 QTableWidgetItem 对象来实现的。使用 QTableWidget 时就需要 QTableWidgetItem,用来表示表格中的一个单元格,整个表格就是用各单元格构建起来的。
QTableWidget类中的常用方法如表:
PyQt5|PyQt5 系统化学习: 表格与树
文章图片
PyQt5|PyQt5 系统化学习: 表格与树
文章图片
如果要设置水平和垂直对齐方式,比如在表格空间内上下、左右居中对齐,那么只要使用 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_())

效果:
PyQt5|PyQt5 系统化学习: 表格与树
文章图片
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_())

效果:
PyQt5|PyQt5 系统化学习: 表格与树
文章图片
17.4.2 在表格中快速定位到指定行 当 tableWidget 表格的行数很多时,可以通过输入行号进行直接定位并显示,比如输入 10,就直接显示第 10行:
import sys from PyQt5.QtWidgets import * from PyQt5 import QtCore from PyQt5.QtGui import QColor, QBrushclass 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_())

效果:
PyQt5|PyQt5 系统化学习: 表格与树
文章图片
17.4.3 设置单元格文本颜色 将表格第一行中三个单元格的文本颜色设置为红色:
import sys from PyQt5.QtWidgets import ( QWidget, QTableWidget, QHBoxLayout, QApplication, QTableWidgetItem) from PyQt5.QtGui import QBrush,QColor,QFontclass 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_())

效果:
PyQt5|PyQt5 系统化学习: 表格与树
文章图片
17.4.4 将字体加粗
import sys from PyQt5.QtWidgets import ( QWidget, QTableWidget, QHBoxLayout, QApplication, QTableWidgetItem) from PyQt5.QtGui import QBrush,QColor,QFontclass 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_())

效果:
PyQt5|PyQt5 系统化学习: 表格与树
文章图片
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 Qtclass 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_())

效果:
PyQt5|PyQt5 系统化学习: 表格与树
文章图片
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 Qtclass 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_())

效果:
PyQt5|PyQt5 系统化学习: 表格与树
文章图片
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_())

效果:
PyQt5|PyQt5 系统化学习: 表格与树
文章图片
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_())

效果如下:
PyQt5|PyQt5 系统化学习: 表格与树
文章图片
17.4.9 在表格中不显示分割线 QTableWidget 类的 setShowGrid()函数是从 QTableView 类继承的,用来设置是否显示表格的分割线,默认显示分割线。使用以下代码,则不显示分割线。
PyQt5|PyQt5 系统化学习: 表格与树
文章图片
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_())

效果如下:
PyQt5|PyQt5 系统化学习: 表格与树
文章图片
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=%dj=%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_())

效果如下:
PyQt5|PyQt5 系统化学习: 表格与树
文章图片
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, Qtclass 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: returnif __name__ == '__main__': app = QApplication(sys.argv) example = Table() example.show() sys.exit(app.exec_())

效果:
PyQt5|PyQt5 系统化学习: 表格与树
文章图片
17.5 QTreeView
QTreeWidget类实现了树形结构。
PyQt5|PyQt5 系统化学习: 表格与树
文章图片
17.5.1 树形结构的实现 树形结构是通过 QTreeWidget 和 QTreeWidgetItem 类实现的,其中 QTreeWidgetItem 类实现了节点的添加。
import sys from PyQt5.QtWidgets import * from PyQt5.QtGui import QIcon,QBrush, QColor from PyQt5.QtCore import Qtclass 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_())

效果:
PyQt5|PyQt5 系统化学习: 表格与树
文章图片
PyQt5|PyQt5 系统化学习: 表格与树
文章图片
PyQt5|PyQt5 系统化学习: 表格与树
文章图片
17.5.2 给节点添加响应事件 演示当单击树形控件时,触发树形控件节点的响应事件。其完整代码如下:
from PyQt5.QtWidgets import * import sysclass 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=https://www.it610.com/article/%s" % (item.text(0), item.text(1)))if __name__ == '__main__': app = QApplication(sys.argv) tree = TreeWidgetDemo() tree.show() sys.exit(app.exec_())

效果如下:
PyQt5|PyQt5 系统化学习: 表格与树
文章图片
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|PyQt5 系统化学习: 表格与树】效果如下:
PyQt5|PyQt5 系统化学习: 表格与树
文章图片

    推荐阅读