PyQt5高级界面控件
表格与树
表格用过QTableWidget,但树没用过
QTableWidget继承自QTableView,主要区别就是QTableView可以使用自定义的数据模型来显示内容(通过setModel来绑定数据源)
QTableWidget中的单元格数据是通过QTableWidgetItem对象来实现的。QTableWidget中对表格元素的处理比较优秀,又元素居中,字体如何显示等,修改单元格样式(大概是它是一个一个元素的设置把)
为什么要用表单,因为表单常常可以用来显示数据库的数据。
from PyQt5.QtSql import QSqlDatabase , QSqlQueryModel , QSqlQuery
pyqt5中的QSqlDatabase
# 添加数据库类型
self.db = QSqlDatabase.addDatabase('QSQLITE')
# 设定数据库名称
self.db.setDatabaseName('./db/database.db')
# 打开数据库
self.db.open()
QSqlQueryModel 对sql的查询结果集进行封装
# 声明查询模型
self.queryModel = QSqlQueryModel(self)
# 设置模型到表单列表
self.tableView.setModel(self.queryModel)
# 设置表格表头
self.queryModel.setHeaderData(0,Qt.Horizontal,"编号")
self.queryModel.setHeaderData(1,Qt.Horizontal,"姓名")
self.queryModel.setHeaderData(2,Qt.Horizontal,"性别")
self.queryModel.setHeaderData(3,Qt.Horizontal,"年龄")
self.queryModel.setHeaderData(4,Qt.Horizontal,"院系")
将数据库数据写入到表单中,也就是将数据模型写入到表单列表
self.tableView.setModel(self.queryModel)
QSqlQuery 类似于游标对象
# 声明数据库查询对象
query = QSqlQuery()
# 创建表
query.exec("create table student(id int primary key, name vchar, sex vchar, age int, deparment vchar)")
QTableView常常使用setModel来绑定数据源
# 设置模型
self.tableView.setModel(self.queryModel)
QTableWidget表格中单元格数据是通过QTableWidgetItem对象来实现的。
这个常用方法很多,但好像都没有与数据库相关联的,也许是由于该数据展现的数据是一个个QTableWidgetItem对象的。
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)
## 填充数据
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)
表格的样式
常见的修饰样式有哪些呢,字体,单元格,表格
待补
QTreeView
树形结构QTreeView是通过QTreeWidget和QTreeWidgetItem类实现的,QTreeWidgetItem类实现了节点的添加。
self.tree = QTreeWidget()
# 设置列数
self.tree.setColumnCount(2)
# 设置头的标题
self.tree.setHeaderLabels(['Key','Value'])
root= QTreeWidgetItem(self.tree)
# 这里设置两次setText是为了,第一次是为了设置key 第二次是为了设置Value
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.tree.expandAll()
self.setCentralWidget(self.tree) # Widgt中设置居中展示吧
常用方法
容器
容器肯定有多种容器,没用过
QStackedWidget
堆栈窗口控件,在同一时间只有一个控件可以显示
QTabWidget
是个控件,控件提供了一个选项卡和一个页面区域,默认显示第一个选项卡的页面。可以通过addTab()将一个控件添加到Tab控件的选项卡中。
当页面较窄的时候,会自动生成箭头来导航标签的切换。
QListWidget
是一个基于条目的接口,用于从列表中添加或删除条目。
QDockWidget是一个可以停靠在QMainWindow内的窗口控件,它可以保持在浮动状态或者在指定位置作为子窗口附加到主窗口中。
意思就是类似于隐藏控件了。
def __init__(self, parent=None):
super(DockDemo, self).__init__(parent)
layout = QHBoxLayout()
bar=self.menuBar() # 菜单栏工具状态的使用
file=bar.addMenu("File") # 菜单名
file.addAction("New") # 菜单项
file.addAction("save")
file.addAction("quit")
self.items = QDockWidget("Dockable", self) # 创建可停靠的窗口
self.listWidget = QListWidget()
self.listWidget.addItem("item1")
self.listWidget.addItem("item2")
self.listWidget.addItem("item3")
self.items.setWidget(self.listWidget)
self.items.setFloating(True) # 代表可以悬浮在主控件外
self.setCentralWidget(QTextEdit()) # 中间显示文本输入框;这个单独的可以拉伸
self.addDockWidget(Qt.RightDockWidgetArea, self.items) # 停靠在窗口的右侧
self.setLayout(layout)
self.setWindowTitle("Dock 例子")
cQFrame
具体作用未知,常常用在分割QSplitter拆分器中
hbox = QHBoxLayout(self)
splitter2 = QSplitter(Qt.Vertical) # 拆分器
bottom = QFrame() # bottom
bottom.setFrameShape(QFrame.StyledPanel)
splitter2.addWidget(bottom )# 添加控件
#设定最终布局
hbox.addWidget(splitter2)
self.setLayout(hbox)
不常用
QMdiArea
MDI多文档界面;可创建多个独立的窗口
子窗口都可以放在主窗口容器中,这个容器控件就是QMdiArea
子窗口在MDI区域进行级联排列布局
QScrollBar
提供水平或者垂直的滑动条
多线程
多线程中常使用信号与槽
计时器模块QTimer(定时器)
周期性的检测主机的CPU值
Qthread
事件处理
网页交互
信号与槽
Pyqt5中信号与槽通过object.signal.connect()方法连接,其实在早期的GUI编程中使用的是回调机制,然后QT中采用了这种新机制信号与槽。
概念:当事件或者状态发生改变时,就会发出信号。同时,信号会触发所有与这个事件(信号)相关的函数(槽)。信号与槽可以是多对多的关系。一个信号可以连接多个槽,一个槽可以连接多个信号。
过程:发送者(emit发送信号)-->接收者(connect绑定信号与槽函数)-->槽函数
定义:在Pyqt5中使用pyqtSignal()函数来为QObject创建一个信号,使用pyqtSingnal()函数可以把信号定义为类的属性
创建信号
# 参数类型是标准的Python数据类型
Signal_name = pyqtSignal() # 括号中可加参数
操作信号
# 绑定槽函数上
connect()
# 解绑
disconnect()
分类:
1.内置信号与槽(内置信号:btn.clicked,槽:showMsg)
widget = QWidget()
def showMsg():
QMessageBox.information(widget, "信息提示框", "ok,弹出测试信息")
btn = QPushButton( "测试点击按钮", widget) # 这种方式添加到QWidget中
btn.clicked.connect( showMsg)
widget.show()
2.自定义信号与槽
# 信号对象
class QTypeSignal(QObject):
# 定义一个信号
sendmsg = pyqtSignal(object)
a_msg = pyqtSignal(object)
def __init__(self):
super(QTypeSignal, self).__init__()
def run(self):
# 发射信号
self.sendmsg.emit('Hello Pyqt5')
self.a_msg.emit('大啊啊')
# 槽对象
class QTypeSlot(QObject):
def __init__(self):
super(QTypeSlot, self).__init__()
# 槽对象里的槽函数
def get(self, msg):
print("QSlot get msg => " + msg)
if __name__ == '__main__':
send = QTypeSignal()
slot = QTypeSlot()
# 1
print('--- 把信号绑定到槽函数 ---')
send.sendmsg.connect(slot.get)
send.run()
send.run()
# 2
print('--- 把信号断开槽函数 ---')
send.sendmsg.disconnect(slot.get)
send.a_msg.connect(slot.get)
send.run()
1,2组合应用,自定义信号和槽函数(自定义信号:self.button_clicked_signal,自定义槽函数btn_close)
button_clicked_signal = pyqtSignal()
def __init__(self,parent=None):
super().__init__(parent)
self.setWindowTitle('自定义信号和槽函数示例')
self.resize(330, 50 )
btn = QPushButton('关闭', self)
# 连接 信号和槽
btn.clicked.connect(self.btn_clicked)
# 接收信号,连接到自定义槽函数
self.button_clicked_signal.connect(self.btn_close)
def btn_clicked(self):
# 发送自定义信号,无参数
self.button_clicked_signal.emit()
## 自定义槽函数 槽函数一般均可自定义的
def btn_close(self):
self.close()
注意点:信号发出的参数个数一定要大于槽函数接收的参数个数
解决方法是用
- 1.lambda表达式
button1.clicked.connect(lambda: self.onButtonClick(1))
- 2.functools中的partial函数
button1.clicked.connect(partial(self.onButtonClick, 1))
button2.clicked.connect(partial(self.onButtonClick, 2))
3.装饰器的信号与槽的使用
就是通过装饰器的方法来定义信号和槽函数
self.okButton = QPushButton("OK", self)
#使用setObjectName设置对象名称
self.okButton.setObjectName("okButton")
layout = QHBoxLayout()
layout.addWidget(self.okButton)
self.setLayout(layout)
# 根据信号名称自动连接到槽函数的核心代码
QtCore.QMetaObject.connectSlotsByName(self)
# 触发按钮和信号的 装饰器
@QtCore.pyqtSlot() # 装饰器函数的下方名称是使用setObjectName绑定的才可以触发的。
def on_okButton_clicked(self):
print( "点击了OK按钮")