如何查看widget类及其子类有哪些属性和函数:
dir()
from PyQt5.QtWidgets import QWidget
dir(QWidget)
help()
from PyQt5.QtWidgets import QWidget
help(QWidget)
表格与树
表格与树解决的问题是如何在一个控件种有规律地呈现更多的数据。PyQt提供了两种控件类用于解决该问题,其中一种是表格结构的控件类;另外一种是树形结构的控件类。
QTableView
在通常情况下,一个应用需要和一批数据(比如数组、列表)进行交互,然后以表格的形式输出这些信息,这时就要用到QTableView类了。在QTableView中可以使用自定义的数据模型来显示内容,通过setModel来绑定数据源。
QTableVidget继承自QTableView,主要区别是QTableView可以使用自定义的数据模型来显示内容(先通过setModel来绑定数据源),而QTableWidget只能使用标准的数据模型,并且其单元格数据是通过QTableWidgetItem对象来实现的。通常使用QTableWidget就能够满足我们的要求。
QTableView控件可以绑定一个模型数据用来更新控件上的内容,可用的模式如表:
名称 | 含义 |
---|---|
QStringListModel | 存储一组字符串 |
QStandarItemModel | 存储任意层次结构的数据 |
QDirModel | 对文件系统进行封装 |
QSqlQueryModel | 对SQL的查询结果集进行封装 |
QSqlTableModel | 对SQL中的表格进行封装 |
QSqlRelationalTableModel | 对带有foreign key的SQL表格进行封装 |
QSortFilterProxyModel | 对模型中的数据进行排序或过滤 |
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)
dlgLayout = QVBoxLayout()
dlgLayout.addWidget(self.tableView)
self.setLayout(dlgLayout)
if __name__ == '__main__':
app = QApplication(sys.argv)
table = Table()
table.show()
sys.exit(app.exec_())
表格并未填满窗口,行和列都又滚动条,可以滑动
QListView
QListView类用于展示数据,它的子类是QListWidget。QListView是基于模型(Model)的,需要程序来建立模型,然后再保存数据。
QListWidget是一个升级版本的QLIstView,它已经建立了要给数据库存储模型(QListWidgetItem),直接调用addItem()函数,就可以添加条目(Item)。
QListView类中的常用方法:
方法 | 描述 |
---|---|
setModel() | 用来设置View所关联的Model,可以使用Python原生的list作为数据源Model |
selectedItem() | 选中Model中的条目 |
isSelected() | 判断Model中的某条目是否被选中 |
QListView类中常用信号:
信号 | 含义 |
---|---|
clicked | 当单击某项时,信号被发射 |
doubleClicked | 当双击某项时,信号被发射 |
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, "ListWidget", "你选择了:" + self.qList[qModelIndex.row()])
if __name__ == '__main__':
app = QApplication(sys.argv)
table = ListViewDemo()
table.show()
sys.exit(app.exec_())
单击QListView控件里Model中的一项时,会弹出消息框
QListWidget
QListWidget类是一个基于条目的接口,用于从列表中添加或删除条目。列表中的每个条目都是一个QLIstWidgetItem对象。QListWidget可以设置多重选择。
QlistWidget类中的常用方法
方法 | 描述 |
---|---|
addItem() | 在列表中添加QListWidgetItem对象或字符串 |
addItems) | 添加列表中的每个条目 |
insertItem() | 在指定的索引处插入条目 |
clear() | 删除列表的内容 |
setCurrentItem() | 设置当前所选条目 |
sortTtems() | 按升序重新排列条目 |
QListWidget类中的常用信号
信号 | 含义 |
---|---|
currentItemChanged | 当列表中的条目发生改变时发射此信号 |
itemClicked | 当点击列表中的条目时发射信号 |
QListWidget的使用
from PyQt5.QtWidgets import *
import sys
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_())
单击QListWidget列表中的一个条目时会弹出消息框,提示选择的是哪个条目。
将QListWidget控件的itemClicked信号与自定义对象的Clicked()槽函数进行绑定
QTableWidget
QTableWIdget是Qt程序中常用的显示数据表格的空间,类似于C#中的DataGrid。QTableWidget是QTableView的子类,它使用标准的数据模型,并且其单元数据是通过QTableWidgetItem对象来实现。使用QTableWidget时就需要QTableWidgetItem,用来表示表格中的一个单元格,整个表格就是用单元格构建起来的。
QTableWidget类中的常用方法
方法 | 描述 |
---|---|
setRowCount(int row) | 设置QTableWidget表格控件的行数 |
setColumnCount(int col) | 设置QTableWidget表格控件的列数 |
setHorizontalHeaderLabels() | 设置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列数。 |
setShowGrid() | 在默认的情况下,表格的显示是有网格线的。True:显示网格线 |
setColumnWidth(int column,int width) | 设置单元格的宽度 |
setRowHeight(int row,int height) | 设置单元格的宽度 |
编辑规则的枚举类型
选项 | 值 | 描述 |
---|---|---|
QAbstractItemView.NoEditTriggers | 0 | 不能对表格内容进行修改 |
QAbstractItemView.CurrentChangedEditing | 1 | 任何时候都能对单元格进行修改 |
QAbstractItemView.DoubleClicked | 2 | 双击单元格 |
QAbstractItemView.SelectedClicked | 4 | 单击已选中的内容 |
QAbstractItemView.EditKeyPressed | 8 | 当修改键被按下时修改单元格 |
QAbstractItemView.anyKeyPressed | 16 | 按任意键修改单元格 |
QAbstractItemView.AllEditTriggers | 31 | 包括以上所有条件 |
表格的选择行为的枚举类型
选项 | 值 | 描述 |
---|---|---|
QAbstractItemView.SelectItem | 0 | 选中单个单元格 |
QAbstractItemView.SelectRows | 1 | 选中一行 |
QAbstractItemView.SelectColumns | 2 | 选中一列 |
单元格文本的水平对齐方式
选项 | 描述 |
---|---|
Qt.AlignLeft | 将单元格的内容沿单元格的左边缘对齐 |
Qt.AlignRight | 将单元格的内容沿右边缘对齐 |
Qt.AlignHCenter | 水平居中 |
Qt.AlignJustify | 将文本在可用空间中对齐,默认从左到右 |
单元格文本的垂直对齐方式
选项 | 描述 |
---|---|
Qt.AlignTop | 顶部对齐 |
Qt.AlignBottom | 底部对齐 |
Qt.AlignVCenter | 垂直居中 |
Qt.AlignBaseline | 基线对齐 |
基本用法
from PyQt5.QtWidgets import *
import sys
class Table(QWidget):
def __init__(self):
super(Table, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle("QTableWidget")
self.resize(400, 300)
conLayout = QHBoxLayout()
tableWidget = QTableWidget()
# 设置表格为4行3列
tableWidget.setRowCount(4)
tableWidget.setColumnCount(3)
conLayout.addWidget(tableWidget)
# 设置表头
tableWidget.setHorizontalHeaderLabels(['姓名', '性别', '体重(kg)'])
newItem = QTableWidgetItem("张三")
# 在第0行0列写入张三
tableWidget.setItem(0, 0, newItem)
newItem = QTableWidgetItem("男")
tableWidget.setItem(0,1,newItem)
self.setLayout(conLayout)
if __name__ == '__main__':
app = QApplication(sys.argv)
example = Table()
example.show()
sys.exit(app.exec_())
在表格控件种显示的数据是可以编辑的
1、设置表格头
# 设置水平表头标签
tableWidget.setHorizontalHeaderLabels(['姓名', '性别', '体重(kg)'])
# 设置垂直表头标签
tableWidget.setVerticalHeaderLabels(['行1','行2','行3','行4'])
注:生成表格,初始化行号和列号后,再设置表格的表头标签,否则没有效果
2、设置表头为伸缩模式
QTableWidget对象的horizontalHeager()函数设置表格为自适应的伸缩模式,即根据窗口大小改变网格大小
tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
3、将表格变为禁止编辑
默认情况下,表格种的字符传是可以修改的,比如双击一个单元格就可以修改原来的内容。如果要禁止这种操作,让表格对用户只是读的,则添加如下代码
tableWidget.setSelectionBehavior(QAbstractItemView.NoEditTriggers)
4、设置表格整行选中
表格默认选中的是的单个单元格,通过以下代码设置成整行选中
tableWidget.setSelectionBehavior(QAbstractItemView.SelectRows)
5、将行和列的宽度、高度设置为与所显示内容的宽度、高度相匹配
QTableWidget.resizeColumnsToContents()
QTableWidget.resizeRowsToContents()
6、表格头的显示与隐藏
对于水平方向的表头,采用以下代码进行隐藏或显示设置
tableWidget。verticalHeader().setVisible(False)
对垂直方向的表头,采用以下代码经行隐藏或显示设置
tableWidget.horizontalHeader().setVisible(False)
7、在单元格中放置控件
QTableWidget不仅允许往单元格放置文字,还允许放置控件,通过TableWidget.setItem()来添加PyQt的基本控件
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};")
tableWidget.setCellWidget(0,2,searchBtn)
8、在表格中快速定位到指定行
当tableWidget表格的行数很多时,可以通过输入行号进行直接定位并显示,比如输入10,直接显示第10行
# 遍历表格查找对应的单元格
item = self.tableWidge.findItems(text,QtCore,Qt.MatchExactly)
# 获取行号
row = item[0].row()
# 模拟鼠标滚轮快速定位到指定行
self.tableWidget.verticalScrollBar().setSliderPosition(row)
from PyQt5.QtWidgets import *
import sys
from PyQt5 import QtCore
from PyQt5.QtGui import QColor, QBrush
class Table(QWidget):
def __init__(self):
super(Table, self).__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)
# 遍历表格查找对应项
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()
# 通过鼠标滚轮定位,快速定位到第11行
tableWidget.verticalScrollBar().setSliderPosition(row)
if __name__ == '__main__':
app = QApplication(sys.argv)
example = Table()
example.show()
sys.exit(app.exec_())
窗口表格会直接显示指定的行,且背景色修改为红色
设置单元格
1、设置单元格文本颜色
将表格第一行中三个单元格的文本颜色设置为红色
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)
2、将字体加粗
newItem = QTableWidgetItem("张三")
newItem.setFont(QFont("Times", 12, QFont.Black))
tableWidget.setItem(0,0,newItem)
3、设置单元格的排序方式
使用Qt.DescendingOrder表示在单元格内降序排列,Qt.AscendingOrder表示在单元格内升序排列
tableWidget.sortItems(2,QtCore.Qt.DescendingOrder)
4、设置单元格文本的对齐方式
使用QTableWidgetItem.setTextAlignment(int)函数设置单元格文本的对齐方式,该函数的参数为对齐方式。
演示第一行第一列的单元格内容右对齐并与底部对齐
tableWidget.setHorizontalHeaderLabels(['姓名','性别','体重(kg)'])
newItem = QTableWidgetItem("张三")
newItem.setTextAlignment(Qt.AlignRight | Qt.AlignBottom)
tableWidget.setItem(0, 0, newItem)
5、合并单元格效果的实现
将表格中第一行第一列的单元格,更改为占据3行1列,核心代码如下
tableWidget.setSpan(0,0,3,1)
6、设置单元格的大小
将第一列的单元格宽度设置为150,第一行的单元格高度设置为120
# 将第一列的单元格宽度设置为150
tableWidget.setColumnWidth(0, 150)
# 第一行的单元格高度设置为120
tableWidget.setRowHeight(0,120)
7、在表格中不显示分割线
QTableWidget类的setShowGrid()函数是从QTableView类继承的,用来设置是否显示表格的分割线,默认显示分割线。使用以下代码,不显示分割线。
tableWidget.setShowGrid(False)
在很多情况下,应用程序中的表格只需要显示水平表头,而不需要显示垂直表头,可以使用如下代码
tableWidget.verticalHeader().setVisible(False)
8、为单元格添加图片
可以在单元格内添加图片,并显示图片的信息描述,核心代码如下
newItem = QTableWidgetItem(QIcon("./images/beibao.png","背包"))
tableWidget.setItem(0,3,newItem)
9、改变单元格中显示图片大小
使用QTableWidget默认处理QTableWidgetItem对象,在每个单元格中放置图片,核心代码如下
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):
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)
10、获取单元格内容
通过实现itemClicked(QTableWidgetItem*)信号的槽函数,可以获得所点击的单元格的引用,进而获得其中的内容。
以下代码将itemClicked信号与getItem()函数进行绑定
tableWidget.itemClicked.connect(self.handleItemClick)
def getItem(self.item):
print("you selected =>" + item.text())
支持右键菜单
from PyQt5.QtWidgets import *
from PyQt5.QtCore import pyqtSignal, QObject, Qt, pyqtSlot
import sys
class Table(QWidget):
def __init__(self):
super(Table, self).__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)
# 将右键菜单绑定到槽函数generateMenu
self.tableWidget.customContextMenuRequested.connect(self.generateMenu)
self.setLayout(conLayout)
def generateMenu(self, 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('true')
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_())
选中单元格后,单击鼠标右键,从弹出的快捷菜单中选择选项。
如果单击张三行,选择选项一,后台输出为:
你选择选项一,当前文字内容是: 张三 男 160
如果单击李四行,选选项一,后台输出为:
你选择选项一,当前文字内容是: 李四 女 170