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按钮")
posted @ 2022-06-07 21:09  索匣  阅读(312)  评论(0编辑  收藏  举报