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_())
效果如下: