表格与树解决的问题是如何在一个控件中有觌律地呈现更多的数据。PyQt提供
了两种控件类用于解决该问题,其中一种是表格结构的控件类:另一种是树形结构
的控件类。
QTableView
在通常情况下,一个应用需要和一批数据(比如数组、列表)进行交互,然后
以表格的形式输出这些信息,这时就要用到QTableView类了。在QtableView中可
以使用自定义的数据模型来显示内容,通过来绑定数据源。
QTableWidget继承自QTableView,主要区别是QTableView可以使用自定义的
数据模型来显示内容(先要通过setModel来绑定数据源),而QTableWidget只能使
用标准的数据模型,并且其单元格数据是通过QTableWidgetItem对象来实现的。通
常使用QTableWidget就能够满足我们的要求。
QTableView控件可以绑定一个模型数据用来更新控件上的内容,可用的模式如
表5-1所示。
方法 | 描述 |
---|---|
QStringListModel | 存储一组字符串 |
QStandardItemModel | 存储任意层次结的数据 |
QDirModel | 对文件系统进行封装 |
QSqlQueryModel | 对SQL的查询结果集进行封装 |
QSqlTableModel | 对SQL中的表格进行封装 |
QSqlRelationalTableModel | 对带有foreign key的SQL表格进行封装 |
QSortFilterProxyModel | 对模型中的数据进行排序或过滤 |
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(['标题','标题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_())
QTabIeView的使用
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(['标题','标题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_())
运行结果
从上图可以看出,表格并没有填满窗口,每列可以自由拉动,但是可能会出
现滚动条。
(1)需要表格填满窗口,可以添加下面代码。
self.tableView.horizontalHeader().setStretchLastSection(True)
self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
(2)添加数据。
self.model.appendRow([
QStandardItem("row %s,column %s"%(11,11)),
QStandardItem("row %s,column %s"%(11,12)),
QStandardItem("row %s,column %s"%(11,13)),
QStandardItem("row %s,column %s"%(11,14)),
])
(3)删除当前选中的数据。
第一种方法:
#取当前选中的所有行
indexs=self.tableView.selectionModel().selection().indexes()
if len(indexs)>0:
#取第一行的索引
index=indexs[0]
self.model.removeRows(index.row(),1)
第二种方法:
index=self.tableView.currentIndex()
print(index.row())
self.model.removeRow(index.row())
如果在表格中什么也不选,那么默认删除的是第一行,也就是索引为0的行:
选中一行时就删除这一行:选中多行时,如果焦点在最后一行,就删除这一行。
QListView
QListView类用于展示数据,它的子类是QListWidget。QListView是基于模型
(Model)的,需要程序来建立模型,然后再保存数据。
QListWidget是一个升级版本的QListView,它已经建立了一个数据存储模型
(QListWidgetItem),直接调用addltem()函数,就可以添加条目(ltem)。
QListView类中的常用方法如表5-2所示。
方法 | 描述 |
---|---|
setModel() | 用来设置View所关联的ModeI,可以使用Python原生的list作为数据源 |
Model | |
selectedItem() | 选中ModeI中的条目 |
isSelected() | 判断Model中的某条目是否被选中 |
QListView类中的常用信号如表5-3所示。
信号 | 含义 |
---|---|
clicked | 当单击某项时,信号被发射 |
doubleClicked | 当双击某项时,信号被发射 |
QListView的使用
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QListWidget, QMessageBox, QListView
from PyQt5.QtCore import QStringListModel
import sys
class ListViewDemo(QWidget):
def __init__(self,parent=None):
super(ListViewDemo,self).__init__(parent)
self.setWindowTitle("ListViewDemo")
self.resize(300,270)
layout = QVBoxLayout()
listView = QListView()
slm=QStringListModel()
self.qList=['Item1','Item2','Item3','Item4']
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_())
运行结果
运行脚本,显示效果如图5-3所示。
在这个例子中,当单击QListView控件里Model中的一项时会弹出消息框(提
示选择的是哪一项)。
将QListView控件的clicked信号与自定义对象的cIicked()槽函数进行绑定。
listView.clicked.connect(self.clicked)
QListWidget
QListWidet类是一个基于条目的接口,用于从列表中添加或删除条目。列表中
的每个条目都是一个QListWidgetItem对象。QListWidget可以设置为多重选择。
QListWidget类中的常用方法如表5-4所示。
方法 | 描述 |
---|---|
addItem() | 在列表中添加QListWidgetltem对象或字符串 |
addItems() | 添加列表中的每个条目 |
insertItem() | 在指定的索引处插入条目 |
clear() | 删除列表的内容 |
setCurrentItem() | 设置当前所选条目 |
sortItems() | 按升序重新排列条目 |
QListWidget类中的常用信号如表5-5所示。
信号 | 含义 |
---|---|
currentItemChanged | 当列表中的条目发生改变时发射此信号 |
itemClicked | 当点击列表中的条目时发射此信号 |
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("Item1")
listWidget.addItem("Item2")
listWidget.addItem("Item3")
listWidget.addItem("Item4")
listWidget.setWindowTitle('QListWidget 例子')
listWidget.itemClicked.connect(listWidget.itemClicked)
listWidget.show()
sys.exit(app.exec_())
运行结果
代码分析:
在这个例了中,当单击QListWidget列表中的一个条目时会弹出消息框,提示
选择的是哪个条目。
将QListWidget控件的itemClicked信号与自定义对象的Clicked()槽函数进行绑定。
listWidget.itemClicked.connect(listWidget.itemClicked)
QTabIeWidget
QTableWidget是Qt程序中常用的显示数据表恪的空间,类似于C#中的
DataGrid。QTableWidget是QTableView的子类,它使用标准的数据模型,并且其单元格数据是通过QTableWidgetItem对象来实现的。使用QTableWidget时就需要
QTableWidgetItem,用来表示表格中的一个单元格,整个表格就是用各单元格构建
起来的。
QTableWidget类中的常用方法如表5-6所示。
方法 | 描述 |
---|---|
setRowCount(int row) | 设置QTableWidget表格控件的行数 |
setColumnCount(int col) | 设置QTableWidget表格控件的列数 |
setVerticalHeaderLabels() | 设置QTableWidget表格控件的水平标签 |
setVerticalHeaderLabels() | 设置QTableWidget表格控件的垂直标签 |
setItem(int,int,QTableWidgetItem) | 在QTableWidget表格控件的每个选顼的单元空间里添加控件 |
horizontalHeader() | 获待QTableWidget表格控件的表格头,以便执行隐藏 |
rowCount() | 获得QTableWidget表格控件的行数 |
columnCount() | 获得QTableWidget表格控件的列数 |
setEditTriggers(EditTriggers triggers | 设置表格是否可编辑。设置编辑规则的枚举值 |
setSelectionBehavior | 设置表格的选择行为 |
setTextAlignment() | 设置单元格内文字的对齐方式 |
setSpan(int row,int column,int rowSpanCount,int columnSpanCount) | 合并单元格,要改变单元格的第row行第column列,要合并rowSpanCount行数和columnSpanCount列数。row:要改变的单元格行数;column:要改变的单元格列数;rowSpanCount:需要合并的行数;columnSpanCount:需要合并的列数 |
setShowGrid() | 在默认况下,表格的显示是有网格线的;True:显示网格线;False:不显示网格线 |
setColumnWidth(intcolumn,int width) | 设置单元格行的宽度 |
setRowHeight(int row,int height) | 设置单元格列的高度 |
编辑规则的枚举值类型如表5-7所示。
选项 | 值 | 描述 |
---|---|---|
QAbstractItemView.NoEditTriggers0No | 0 | 不能对表格内容行修改 |
QAbstractItemView.CurrentChanged1Editing | 1 | 任何时候都能对单元格进行修改 |
QAbstractItemView.DoubleClicked2Editing | 2 | 双击单元格 |
QAbstractItemView.SelectedClicked4Editing | 4 | 单击己选中的内容 |
QAbstractItemView.EditKeyPressed8Editing | 8 | 当修改被按下时修改单元格 |
QAbstractItemView.EditKEyPressed16Editing | 16 | 按任意键修改单元格 |
QAbstractItemView.AllEditTrigger31Editing | 31 | 包括以上所有条件 |
表格的选择行为的枚举值类型如表5-8所示。
选项 | 值 | 描述 |
---|---|---|
QAbstractItemView.SelectItems0Selecting | 0 | 选中单个单元格 |
QAbstractItemView.SelectRowsSelecting | 1 | 选中一行 |
QAbstractItemView.SelectColns2Selecting | 2 | 选中一列 |
单元恪文本的水平对齐方式如表5-9所示。
选项 | 描述 |
---|---|
Qt.AlignLeft | 与顶部对齐 |
Qt.AlignRight | 与底部对齐 |
Qt.AlignHCenter | 在可用空间中,居中显示在垂直方向上 |
Qt.AlignJustify | 与基线对齐 |
单元格文本的垂直对齐方式如表5-10所示。
选项 | 描述 |
---|---|
Qt.AlignTop | 与顶部对齐 |
Qt.ALignBottom | 与底部对齐 |
Qt.ALignVCenter | 在可用空间中,居中显示在垂直方向上 |
Qt.AlignBaseline | 与基线对齐 |
如果要设置水平和垂直对齐方式,比如在表格空间内上下、左右居中对齐,那
么只要使用QLAlignHCenter和Qt.AlignVCenter即可。
基本用法
import sys
from PyQt5.QtWidgets import (QWidget, QTabWidget, QHBoxLayout, QTableWidget, QAbstractItemView, QTableWidgetItem,
QApplication)
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.verticalHeader().setVisible(False)
self.setLayout(conLayout)
if __name__ == '__main__':
app = QApplication(sys.argv)
example=Table()
example.show()
sys.exit(app.exec_())
运行结果:
代码分析:
self.table=QTableWidget(4,3)
上面这行代码构造了一个QTableWidget对象,并且设置表格为4行3列。
tableWidget.setHorizontalHeaderLabels(['姓名','性别','体重(kg)'])
上面这行代码设置了表格头。
newItem=QTableWidgetItem("张三")
上面这行代码生成了一个QTableWidgetItem对象,名称为"张三"。
上面这行代码将刚才生成的具体单元格加载到表格的第0行第0列处。
在默认情况下,表格里的字符串是可以更改的。
设置表格头
import sys
from PyQt5.QtWidgets import (QWidget, QTabWidget, QHBoxLayout, QApplication, QTableWidget, QHeaderView,
QTableWidgetItem)
class Table(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle("QTableWidget demo")
self.resize(500,300)
conLayout=QHBoxLayout()
tableWidget=QTableWidget()
tableWidget.setRowCount(4)
tableWidget.setColumnCount(3)
conLayout.addWidget(tableWidget)
tableWidget.setHorizontalHeaderLabels(['姓名','性别','体重(kg)'])
tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
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_())
运行截图
首先,初始化QTableWidget的实例对象,生成一个4行3列的表格。
tableWidget.setRowCount(4)
tableWidget.setColumnCount(3)
conLayout.addWidget(tableWidget)
然后,设置表格的水平表头标签和垂直表头标签。
tableWidget.setHorizontalHeaderLabels(['姓名','性别','体重(kg)'])
tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
生成表格,初始化行号和列号后,再设置表格的表头标签,否则是没有效果的。
设置表格头为伸缩模式。
创建一个4行3列的表格,表格头信息“姓名”“性别”“体重(kg)"水平放置,
不设置表格的垂直表头标签,然后使用QTableWidget对象的horizontalHeager()函数
设置表格为自适应的伸缩模式,即可根据窗口大小来改变网格大小。
tableWidget=QTableWidget()
tableWidget.setRowCount(4)
tableWidget.setColumnCount(3)
conLayout.addWidget(tableWidget)
tableWidget.setHorizontalHeaderLabels(['姓名','性别','体重(kg)'])
tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
将表格变为禁止编辑
在默认情况下,表格中的字符串是可以更改的,比如双击一个单元格,就可以修
改原来的内容。如果想禁止这种操作,让表格对用户是只读的,则可以编写如下代码。
tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
设置表格整行选中
表格默认选中的是单个单元格,通过下面的代码可以设置成整行选中。
tableWidget.setSelectionBehavior(QAbstractItemView.SelectRows)
将行和列的宽度、高度设置为与所显示内容的宽度、高度相匹配
QTableWidget.resizeColumnToContents()
QTableWidget.resizeColumnToContents()
表格头的显示与隐藏
tableWidget.verticalHeader().setVisible(False)
对于垂直方向的表头,采用以下代码进行隐藏或显示没置。
tableWidget.horizontalHeader().setVisible(False)
在单元格中放置控件
QTableWidget不仅允许往单元格中放置文字,还允许放置控件,通过
TableWidget.setltem()来添加PyQt的基本控件。
import sys
from PyQt5.QtWidgets import (QWidget,QTableWidget,QHBoxLayout,QApplication,QTableWidgetItem,QAbstractItemView,QComboBox,QPushButton)
class Table(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle("QTableWidget 例子")
self.resize(430,300)
conLayout=QHBoxLayout()
tableWidget=QTableWidget()
tableWidget.setRowCount(4)
tableWidget.setColumnCount(3)
conLayout.addWidget(tableWidget)
tableWidget.setHorizontalHeaderLabels(['姓名','性别','体重(kg)'])
newItem=QTableWidgetItem("张三")
tableWidget.setItem(0,0,newItem)
comBox=QComboBox()
comBox.addItem("男")
comBox.addItem("女")
comBox.setStyleSheet("QComboBox{margin:3px};")
tableWidget.setCellWidget(0,1,comBox)
searchBtn=QPushButton("修改")
searchBtn.setDown(True)
searchBtn.setStyleSheet("QPushButton{margin:3px};")
self.setLayout(conLayout)
if __name__ == '__main__':
app = QApplication(sys.argv)
example=Table()
example.show()
sys.exit(app.exec_())
运行结果
在表格中快速定位到指定行
当tableWidget表格的行数很多时,可以通过输入行号进行直接定位并显示,比
如输入10,就直接显示第10行。
#遍历表格查找对应的具体单元格
item=self.tableWidget.findItem(text,Qt.MatchFixedString)
#获取其行号
row=item[0].row()
#模拟鼠标滚轮快定位到指定行
self.tableWidget.verticalScrollBar().setSliderPosition(row)
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_())
运行结果