Skip to content

高级组件

PyQt5除了常用控件外,还有一些关于进度、展示数据等的高级控件


进度条类控件

进度条类控件主要显示任务的执行进度,PyQt5提供了进度条控件和滑块控件这两种类型的进度条控件。其中,进度条控件是我们通常所看到的进度条,用ProgressBar控件表示

ProgressBar

ProgressBar控件表示进度条,通常在执行长时间任务时,用进度条告诉用户当前的进展情况。

ProgressBar控件对应PyQt5中的QProgressBar类,它其实就是QProgressBar类的一个对象

ProgressBar继承自QWidget

功能作用
创建控件
  • QProgressBar(self)

具体形式:pb = QProgressBar(self)

一开始创建的控件是没有展示进度的,需要后续的设置

设置范围和当前值
API描述
setMinimum(int)设置进度条的最小值,默认值为0
setMaximum(int)设置进度条的最大值,默认为100
setRange(int, int)设置显示的值域范围
setValue(int)设置当前值
reset()重置进度条
value()获取当前的数值

注意:如果设置最大值和最小值如果都是0, 则进入繁忙提示(进度条一直在滑动)

格式设置

除了进度条部分外,其控件还有一个字符串来显示进度,默认是以百分比形式的,格式设置主要设置文本的展示内容和格式字符串的对齐方式

API描述
setFormat(str)设置展示字符的格式,其中参数:%p:百分比;%v:当前值;%m:总值
resetFormat()重置字符格式,变回之前的默认情况,即百分比形式
setAlignment(Qt.AlignmentFlag)设置格式字符对齐方式(设置字符串的位置格式)有水平和垂直两种,分别如下:水平对齐方式:Qt.AlignLeft:左对齐;Qt.AlignHCenter:水平居中对齐;Qt.AlignRight:右对齐;Qt.AlignJustify:两端对齐;垂直对齐方式:Qt.AlignTop:顶部对齐;Qt.AlignVCenter:垂直居中;Qt.AlignBottom:底部对齐
文本操作
API描述
setTextVisible(bool)设置文本标签是否显示,默认是True
text()获取文本内容
setTextDirection(QProgressBar.Direction)设置文本方向,仅仅对于垂直进度条有效,其中枚举值为:QProgressBar.TopToBottom:从上到下;QProgressBar.BottomToTop:从下到上
设置进度条方向

通过setOrientation(Qt.Orientation)方法设置进度条的方向,默认情况下是水平方向

其中参数Qt.Orientation有以下的枚举值:Qt.Horizontal:设置进度条水平;Qt.Vertical:设置进度条垂直

修改的仅仅是方向,控件的尺寸需要自己调节,这样才能更好的进行展示

倒立外观

对于水平方向的进度条,滑动方向是从左往右的,对于垂直方向,滑动方向是从下往上的

若想其滑动方向变为从右往左和从上往下,可以通过setInvertedAppearance(True)方法进行设置翻转

其他方法
API描述
setLayoutDirection()设置进度条的布局方向,支持以下3个方向值:Qt.LeftToRight:从左至右;Qt.AlignHCenter:水平居中对齐;Qt.LayoutDirectionAuto:跟随布局方向自动调整
setProperty()对进度条的属性进行设置,可以是任何属性,如self.progressBar.setProperty("value", 24)
相关信号
API描述
valueChanged(int)值发生改变时发射信号
案例--进度条1秒加1

创建进度条控件,让其以1秒递增1,按钮可以控制进度条停止和开始,点击stop,进度条就会停止增加

代码中使用的QBasicTimer类是QtCore模块中包含的一个类,主要用来为对象提供定时器事件。QBasicTimer定时器是一个重复的定时器,除非调用stop()方法,否则它将发送后续的定时器事件。启动定时器使用start()方法,该方法有两个参数,分别为超时时间(毫秒)和接收事件的对象,而停止定时器使用stop()方法即可。


表格

表格与树可以使一个控件中有规律地呈现更多数据,PyQt提供了两种控件类用于解决该问题,一种是表格结构的控件类;另一个是树型结构的控件类。

QTableView

一个应用要和一批数据(数组、列表)进行交互,然后以表格的形式输出这些信息,就要使用QTableView类,QTableView类可以使用自定义的数据模型来显示内容,通过setModel来绑定数据。QTableWidget继承自QTableViewQTableWidget只能使用标准的数据模型,其单元格数据通过QTableWidgetItem对象来实现。

QTableView控件可以绑定一个模型数据用来更新控件上的内容,可用的模式:

名称含义
QStringListModel存储一组字符串
QStandardItemModel存储任意层次结构的数据
QFileSystemModel存储本地系统的文件和目录信息(针对当前项目)
QDirModel对文件系统进行封装
QSqlQucryModelSQL的查询结果进行封装
QSqlTableModelSQL中的表格进行封装
QSqlRelationalTableModel对带有foreign keySQL表格进行封装
QSortFilterProxyModel对模型中的数据进行排序或过滤
案例--QTableView的使用
python
# -*- coding: utf-8 -*- 

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);   # 创建表存储任意层次结构的数据,表格是4*4的
		self.model.setHorizontalHeaderLabels(['标题1','标题2','标题3','标题4'])  # 创建列标题
        self.model.setVerticalHeaderLabels(['数据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_())

程序运行结果:其表格的每一列/行可以自由拉动

要想固定每行/列的大小,使其不能被鼠标拉动,需要进行以下设置:

python
# 下面代码让表格100填满窗口
self.tableView.horizontalHeader().setStretchLastSection(True)
self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

程序运行结果如下:我们不能再用鼠标去拉动单元格的大小

添加数据:

python
self.model.appendRow([QStandardItem("row %s, column %s"%(11,11)),
					  QStandardItem("row %s, column %s"%(22,22)),
					  QStandardItem("row %s, column %s"%(33,33)),
					  QStandardItem("row %s, column %s"%(44,44)),
					  ])

程序运行结果如下:在第五行进行了一个数据的添加

删除数据:

删除当前选中的数据:

python
indexs = self.tableView.selectionModel().selection().indexes()   #获取当前选中的所有行
if len(indexs) > 0:
    index = indexs[0]   #获取第一行索引,第一行,索引为0
    self.model.removeRows(index.row(), 1)

QListView

QListView用于展示数据,它的子类是QListWidgetQListView是基于模型(Model)的,需要用程序建立模型,再保存数据。

QListWidget是一个升级版本的QListView,它建立了一个数据存储模型(QListWidgetItem),直接调用addItem函数,就可以调用条目item

QListView类中的常用方法:

方法描述
setModel()用来设置View所关联的Model,可以使用Python原生的list作为数据源Model
selectedItem()选中Model中的条目
isSelected()判断Model中的某条目是否被选中

QListView类中常用的信号:

信号含义
clicked当单击某项时,信号被发射
doubleClicked当双击某项时,信号被发射
案例--QListView的使用

单击QListView控件里Model中的一项时弹出消息框用来提示选择了哪一项

python
# -*- coding: utf-8 -*-

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()
		# 创建QListView
		listView = QListView()      
		slm = QStringListModel();  # 设置为存储一组字符串的模式
		self.qList = ['Item 1','Item 2','Item 3','Item 4' ]	
		slm.setStringList(self.qList)
		listView.setModel(slm)  # 设置View所关联的Model
		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_())

QListWidget

QListWidget类是一个基于条目的接口,用于从列表中添加或删除条目。列表中的每个条目都是一个QListWidgetltem对象。QListWidget可以设置为多重选择。

QListWidget类中常用的方法:

方法描述
addltem()在列表中添加QListWidgetltem对象或字符串
addltems()添加列表中的每个条目
insertltem()在指定的索引处插入条目
clear()删除列表的内容
setCurrentltem()设置当前所选条目
sortltems()按升序重新排列条目

QListWidget类中常用的信号:

信号含义
currentltemChanged当列表中的条目发生改变时发射此信号
itemClicked当点击列表中的条目时发射此信号
案例--QListWidget的使用
python
# -*- coding: utf-8 -*-

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_())

QTableWidget

QTableWidget是常用的显示数据表格的控件,QTableWidgetQTableView的子类, 它使用标准的数据模型,并且其单元格数据是通过QTableWidgetltem对象来实现的。

使用QTableWidget时需要QTableWidgetltem,用来表示表格中的一个单元格,整个表格是用各单元格构建的。

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列数:row:要改变的单元格行数;column:要改变的单元格列数;rowSpanCount:需要合并的行数;columnSpanCount:需要合并的列数
setShowGrid()在默认情况下,表格的显示是有网格线的:True:显示网格线;False:不显示网格线
setColumn Width(int column, int width)设置单元格行的宽度
setRowHeight(int row, int height)设置单元格列的高度

编辑规则的枚举值类型:

选项描述
QAbstractltemView.NoEditTriggers0No0不能对表格内容进行修改
QAbstractItemView.CurrentChanged1Editing1任何时候都能对单元格进行修改
QAbstractltemView.DoubleClicked2Editing2双击单元格
QAbstractItemView.SelectedClicked4Editing4单击已选中的内容
QAbstractItemView.EditKeyPressed8Editing8当修改键被按下时修改单元格
QAbstractItemView.AnyKeyPressed16Editing16按任意键修改单元格
QAbstractltemView.AllEditTriggers31Editing31包括以上所有条件

表格的选择行为枚举值类型:

选项描述
QAbstractItemView.SelectItems0Selecting0选中单个单元格
QAbstractItemView.SelectRows1Selecting1选中一行
QAbstractItemView.SelectColumns2Selecting2选中一列

单元格文本的水平对齐方式:

选项描述
Qt.AlignLeft将单元格的内容沿单元格的左边缘对齐
Qt.AlignRight将单元格的内容沿单元格的右边缘对齐
Qt.AlignHCenter在可用空间中,居中显示在水平方向上
Qt.AlignJustify将文本在可用空间中对齐,默认是从左到右的

单元格文本的垂直对齐方式:

选项描述
Qt.AlignTop与顶部对齐
Qt.AlignBotom与底部对齐
Qt.AlignVCenter在可用空间中,居中显示在垂直方向上
Qt.AlignBaseline与基线对齐
案例--QTableWidget的使用

在控件中显示的数据是可编辑的:

python
# -*- coding: utf-8 -*- 

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *   # 主要的是QColor和QBrush,用于单元格字体颜色

class Table(QWidget):
	def __init__(self):
		super().__init__()
		self.initUI()

	def initUI(self):
		self.setWindowTitle("QTableWidget 例子")
		self.resize(430,230);
		conLayout = QHBoxLayout()
        #self.table = QTableWidget(4, 3)    # 构造了一个QTableWidget对象,并设置了表格为4行3列
        # 构造表格,初始化QTableWidget的实例化对象,生成一个4行3列的表格
		tableWidget = QTableWidget()
		tableWidget.setRowCount(4)
		tableWidget.setColumnCount(3)
        #tableWidget.setColumnCount(4)   # 添加图片用到的4*4的表格
		conLayout.addWidget(tableWidget)
		# 设置表格头,要在初始化行号和列号之后,否则是没有效果的
		tableWidget.setHorizontalHeaderLabels(['姓名','性别','体重(kg)'])  # 设置了水平表格头
        #tableWidget.setHorizontalHeaderLabels(['姓名','性别','体重(kg)','图片'])  # 添加图片设置的水平表格头
        tableWidget.setVerticalHeaderLabels(['行1', '行2', '行3', '行4'])  # 设置了垂直表格头
        # 设置表格头为伸缩模式,使用时要将设置垂直表格头该行代码禁用
		#tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)  
        
        #tableWidget.setSpan(0,0,3,1)   # 用于合并单元格,将表格第一行第一列(0,0)的单元格,改为占据3行1列(3,1)
        
		newItem = QTableWidgetItem("张三")  # 生成了一个QTableWidgetItem对象,名称为张三,生成的单元格加载到0行0列处
        #newItem.setForeground(QBrush(QColor(255,0,0)))   # 设置单元格中的字体为红色
        #newItem.setFont(QFont("Times", 12, QFont.Black))  # 将字体加粗
        #newItem.setFont(QFont("Times", 12, QFont.Black))  # 设置字体处于右下方,方法一
        #newItem.setTextAlignment( Qt.AlignRight| Qt.AlignBottom )# 设置字体处于右下方,方法二
		tableWidget.setItem(0, 0, newItem)  
        #设置单元格大小
        #tableWidget.setColumnWidth(0, 150)  # 将第一列的单元格宽度设置为150,0表示第一
		#tableWidget.setRowHeight(0, 120)    # 将第一行的单元格高度设置为150,0表示第一
        
        '''
        newItem = QTableWidgetItem("男")  
		tableWidget.setItem(0, 1, newItem)  
		  
		newItem = QTableWidgetItem("160")  
		tableWidget.setItem(0, 2, newItem)
		'''
        '''
        newItem = QTableWidgetItem(QIcon("./images/bao1.png"), "背包")   # 添加图片,并显示其描述信息:背包
		tableWidget.setItem(0, 3, newItem)
        '''
        '''
		# 在单元格中放置控件,来代替上述“男”,“160”的单元格,放入下拉单选框控件
		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)   
		'''
		# 将表格变为禁止编辑,默认情况下,表格中的字符串是可以更改的,双击一个单元格,就可以在上面修改,若想要只读,执行下面代码
		#tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
		
		# 设置表格为整行选择,表格默认选中的是单个单元格,以下代码可以使整行选中
		#tableWidget.setSelectionBehavior( QAbstractItemView.SelectRows)

		# 将行和列的宽度,高度设为与内容的宽度,高度相匹配,与设置表格头为伸缩模式该行代码不能同时使用
		#tableWidget.resizeColumnsToContents()
		#tableWidget.resizeRowsToContents()
		
		# 表格表头的显示与隐藏,使用下面两行代码这隐藏行列表格头
		#tableWidget.verticalHeader().setVisible(False)
		#tableWidget.horizontalHeader().setVisible(False)
		
		# 不显示表格单元格的分割线,单元格不再有线划分
		#tableWidget.setShowGrid(False)
		self.setLayout(conLayout)

if __name__ == '__main__':
	app = QApplication(sys.argv)
	example = Table()  
	example.show()   
	sys.exit(app.exec_())
在表格中快速定位到指定行

当表格的行数很多时,可以通过输入行号进行直接的定位并显示,输入10,就直接显示到第10行,定位一般通过标注颜色或选中单元格来使其凹显,一般情况这两个选择一个使用即可。

python
text = "(10,1)"  # 查找第11行第二列的单元格
items = tableWidget.findItems(text, QtCore.Qt.MatchExactly)  # 遍历表格
item = items[0]
# 选中单元格
#item.setSelected( True)
# 设置单元格的背景颜色为红色
item.setForeground(QBrush(QColor(255, 0, 0)))
row = item[0].row()   # 获取其行号
self.tableWidget.verticalScrollBar().setSliderPosition(row)  # 模拟鼠标滚轮快速定位到指定行,这样定位的行就在表格的上方
设置单元格的排序方式

要想对单元格内进行升/降序排列,需要先导入PyQt5.QtCore模块中的Qt

from PyQt.QtCore import Qt

python
#Qt.DescendingOrder   降序
#Qt.AscendingOrder    升序
tableWidget.sortItems(2, QtCore.Qt.DescendingOrder)  # 以第三列的数据设置降序,2表示第三列
改变单元格中显示的图片大小
python
# -*- coding: utf-8 -*- 

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()
		#创建表格3*5
		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)
       
if __name__ == '__main__':
	app = QApplication(sys.argv)
	example = Table()  
	example.show()   
	sys.exit(app.exec_())
获得单元格的内容
python
tableWidget.itemClicked.connect(self.handleItemClick)
# 槽函数
def getItem(self, item):
    print("你选择的=>" + item.text())
支持右键菜单
python
# -*- coding: utf-8 -*- 

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_())

QTreeView

QTreeView类实现了树型结构,和目录类似,具有分层结构,一级二级标题。

树型结构是通过QTreeWidgetQTreeWidgetItem类实现的,其中QTreeWidgetItem类实现了节点的添加。

QTreeWidget类中的常用方法:

方法描述
setColumnWidth(int column, int width)将指定列的宽度设置为给定的值:Column,指定的列;Width,指定列的宽度
insertTopLevelItems()在视图的顶层索引中插入项目列表
expandAll()展开所有的树形节点
invisibleRootItem()返回树形控件中不可见的根选项(Root Item)
selectedltems()返回所有选定的非隐藏项目的列表

QTreeWidgetItem类中的常用方法:

方法描述
addChild()将子项追加到子列表中
setText()设置显示的节点文本
Text()返回显示的节点文本
setCheckState(column, state)设置指定列的选中状态:Qt.Checked,节点选中;Qt.Unchecked,节点未选中
sctIcon(column, icon)在指定的列中显示图标
案例--QTreeWidget的使用
python
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)   # 其上一级为root
		child1.setText(0,'child1')
		child1.setText(1,'ios')
		child1.setIcon(0,QIcon("./images/IOS.png"))
		child1.setCheckState(0, Qt.Checked)   # 设置节点状态,使用setCheckState()函数设置节点是否为选中状态
				
		# 设置子节点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_())

除了上述方法,还可以通过QTreeWidget.insertToplevelItems()的方法来实现树形结构:

python
self.tree = QTreeWidget()
self.tree.setcolumncount(2)  # 设置列数
self.tree.setHeaderLabels(['Key', 'Value'])  # 设置树形控件头部的标题
# 设置根节点
root= QTreeWidgetItem()
root.setText{0,"root")
 
rootList = []
rootList.append(root)
# 设置树形控件的子节点1
childl = QTreeWidgetItem()
childl.setText(0, 'child1')
child1.setText(l, 'ios')
root.addChild(childl)
 
self.tree.insertToplevelItems(0, rootList)
案例--给节点添加响应事件

使用树型控件时触发树型节点的响应事件,关键是建立信号和槽函数进行连接。

python
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 )  # 点击时发射信号,连接槽函数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_())
案例--系统定制模式
python
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_())

容器

容器用于装载更多的控件,在现有的窗口空间中装载更多的控件。

QTabWidget

QTabWidget控件提供了一个选项卡和一个页面区域,默认显示第一个选项卡的页面,通过单击各选项卡可以查看对应的页面。如果在一个窗口中显示的输入字段很多,可以对这些字段进行拆分,分别放置在不同页面的选项卡中。

QTabWidget类中常用的方法:

方法描述
addTab()将一个控件添加到Tab控件的选项卡中
insertTab()将一个Tab控件的选项卡插入到指定的位置
removeTab()根据指定的索引删除Tab控件
setCurrentIndex()设置当前可见的选项卡所在的索引
setCurrentWidget()设置当前可见的页面
setTabBar()设置选项卡栏的小控件
setTabPosition()设置选项卡的位置:QTabWidget.North:显示在页面上方;QTabWidget.South:显示在页面的下方;QTabWidget.West:显示在页面的左侧;QTabWidget.East:显示在页面的右侧
setTabText()定义Tab选项卡的显示值

QTabWidget类中常用的信号:

信号描述
currentChanged切换当前页面时发射该信号
案例--QTabWidget的使用

一个表单的内容分为三组,每一组小控件都显示在不同的选项卡中,顶层窗口是一个QTabWidget控件,将三个选项卡添加进去:

python
# -*- coding: utf-8 -*-
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_())

QStackedWidget

QStackedWidget是一个堆栈窗口控件,可以填充一些小控件,但同时只有一个小控件可以显示,QStackedWidget使用QStackedLayout布局,可以有效的显示窗口中的控件。

案例--QStackedWidget的使用
python
# -*- coding: utf-8 -*-
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)
        # QListWidget的currentRoeChanged信号与槽函数相关联,改变堆叠控件的视图
		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_())

QDockWidget

QDockWidget是一个可以停靠在QMainWindow内的窗口文件,它可以保持在浮动状态或者在指定位置作为子窗口附加到主窗口中。

QDockWidget控件在主窗口内可以移动到新的区域。

QDockWidget类中常用方法:

方法描述
setWidget()Dock窗口区域设置QWidget
setFloating()设置Dock窗口是否可以浮动,如果设置为True,则表示可以浮动
setAllowedAreas()设置窗口可以停靠的区域:LeftDockWidgetArea:左边停靠区域;RightDockWidgetArea:右边停靠区域;TopDockWidgetArea:顶部停靠区域;BottomDockWidgetArea:底部停靠区域;NoDockWidgetArea:不显示Widget
setFeatures()设置停靠窗口的功能属性:DockWidgetClosable:可关闭;DockWidgetMovable:可移动;DockWidgetFloatable:可漂浮;DockWidgetVerticalTitleBar:在左边显示垂直的标签栏;AllDockWidgetFeatures:具有前三种属性的所有功能;NoDockWidgetFeatures:无法关闭,不能移动,不能漂浮
案例--QDockWidget的使用

顶层窗口是一个QMainWindow对象,QTextEdit对象是它的中央小控件:

python
# -*- coding: utf-8 -*-

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

class DockDemo(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")
        # 创建停靠窗口items,在停靠窗口中添加QListWidget对象
		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(False)
		self.setCentralWidget(QTextEdit())   # QTextEdit对象是它的中央小控件
		self.addDockWidget(Qt.RightDockWidgetArea, self.items) # 将停靠窗口放在中央小控件的右侧
		self.setLayout(layout)
		self.setWindowTitle("Dock 例子")
					
if __name__ == '__main__':
	app = QApplication(sys.argv)
	demo = DockDemo()
	demo.show()
	sys.exit(app.exec_())

QMdiArea

一个GUI应用程序可能有多个窗口,选项卡和堆栈窗口控件允许一次使用其中一个窗口,但某个窗口在使用时,其他窗口的视图是隐藏的,所以我们可以用多文档界面来解决这个问题,其可以创建多个独立的窗口,这些窗口被称为SDI(单文档界面),每个窗口都可以有自己的菜单系统、工具栏等。

MDI(多文档界面)子窗口可以放在主窗口容器中,这个容器控件被称为QMdiArea

QMdiArea控件通常占据QMainWindow对象的中央位置,子窗口在这个区域是QMdiSubWindow类的实例,可以设置任何QWidget作为子窗口对象内部控件,子窗口在MDI区域进行级联排列布局

QMdiArea类和QMdiSubWindow类中常用的方法:

方法描述
addSubWindow()将一个小控件添加在MDI区域作为一个新的子窗口
removeSubWindow()删除一个子窗口中的小控件
setActiveSubWindow()激活一个子窗口
cascadeSubWindows()安排子窗口在MDI区域级联显示
tileSubWindows()安排子窗口在MDI区域平铺显示
closeActiveSubWindow()关闭活动的子窗口
subWindowList()返回MDI区域的子窗口列表
setWidget()设置一个小控件作为QMsiSubwindow实例对象的内部控件
案例--多文档界面的使用

主窗口QMainWindow拥有一个菜单栏控件和MidArea控件

python
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
            
class MainWindow(QMainWindow):
	count=0
	def __init__(self, parent=None):
		super(MainWindow, self).__init__(parent)
		self.mdi = QMdiArea()
		self.setCentralWidget(self.mdi)
		bar=self.menuBar()
		file=bar.addMenu("File")
		file.addAction("New")
		file.addAction("cascade")
		file.addAction("Tiled")
		file.triggered[QAction].connect(self.windowaction)  # 当菜单栏控件触发triggered信号时,连接到槽函数
		self.setWindowTitle("MDI demo")

	def windowaction(self, q): 
		print( "triggered")
		if q.text()=="New":   # 新建一个子窗口,并显示在主窗口中
			MainWindow.count=MainWindow.count+1
			sub=QMdiSubWindow()
			sub.setWidget(QTextEdit())
			sub.setWindowTitle("subwindow"+str(MainWindow.count))
			self.mdi.addSubWindow(sub)
			sub.show()
		if q.text()=="cascade":
			self.mdi.cascadeSubWindows()   # 安排子窗口在MDI区域级联显示
		if q.text()=="Tiled":
			self.mdi.tileSubWindows()    # 安排子窗口在MDI区域平铺显示
             	
if __name__ == '__main__':
	app = QApplication(sys.argv)
	demo = MainWindow()
	demo.show()
	sys.exit(app.exec_())

程序运行结果:新建两个窗口后,安排子窗口在MDI区域级联显示

QScrollBar

QScrollBar使窗口控件提供水平的或垂直的滚动条,使得可以扩大当前窗口的有效装载面积,从而装载更多的控件

QScrollBar类中常用的信号:

信号含义
valueChanged当滑动条的值改变时发射此信号
sliderMoved当用户拖动滑块时发射此信号
案例--QScrollBar的使用

拖动滑动条的值来改变颜色:

python
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

class Example(QWidget):
	def __init__(self):
		super(Example, self).__init__()
		self.initUI()
		
	def initUI(self): 
		hbox = QHBoxLayout( )
		self.l1 = QLabel("拖动滑动条去改变颜色")
		self.l1.setFont(QFont("Arial",16))
		hbox.addWidget(self.l1)
		self.s1 = QScrollBar()
		self.s1.setMaximum(255)
		self.s1.sliderMoved.connect(self.sliderval)  # 当滑块滑动时,将sliderMoved信号和槽函数sliderval连接起来
		self.s2 = QScrollBar()
		self.s2.setMaximum(255)
		self.s2.sliderMoved.connect(self.sliderval)
		self.s3 = QScrollBar()
		self.s3.setMaximum(255)
		self.s3.sliderMoved.connect(self.sliderval)
		hbox.addWidget(self.s1)
		hbox.addWidget(self.s2)
		hbox.addWidget(self.s3)
		self.setGeometry(300, 300, 300, 200)
		self.setWindowTitle('QScrollBar 例子')
		self.setLayout( hbox )
		
	def sliderval(self):
		print( self.s1.value(),self.s2.value(), self.s3.value() )
		palette = QPalette()
		c = QColor(self.s1.value(),self.s2.value(), self.s3.value(),255)
		palette.setColor(QPalette.Foreground,c)
		self.l1.setPalette(palette)

if __name__ == '__main__':
	app = QApplication(sys.argv)
	demo = Example() 	
	demo.show()
	sys.exit(app.exec_())

多线程

多线程技术涉及三种方法:使用计时器模块QTimer,使用多线程模块QThread和使用事件处理的功能。

QTimer

如果需要应用程序周期性地进行某项操作,就需要用到QTimer实例,将其timeout信号连接到相应的槽,调用start(),之后定时器会以恒定的间隔发出timeout信号。

使用时首先要引入QTimer模块:from PyQt5.QtCore import QTimer

QTimer类常用的方法:

方法描述
start(milliseconds)启动或重新启动定时器,时间间隔为毫秒,如果定时器已经运行,它将被停止并重新启动,如果singleShot信号为真,定时器将仅被激活一次
Stop()停止定时器

QTimer类中常用的信号:

信号描述
singleShot在给定的时间间隔后调用一个槽函数时发射此信号
timeout当定时器超时时发射此信号
python
self.timer = QTimer(self)  # 初始化一个定时器
self.timer.timeout.connect(self.operate)  # 计时结束调用operate()方法
self.timer.start(2000)  # 设置计时器时间间隔并启动计时器
案例--QTimer的使用

时间显示

python
# -*- coding: utf-8 -*- 
from PyQt5.QtWidgets import QWidget,  QPushButton ,  QApplication ,QListWidget,  QGridLayout , QLabel
from PyQt5.QtCore import QTimer ,QDateTime
import sys 

class WinForm(QWidget):  
	def __init__(self,parent=None): 
		super(WinForm,self).__init__(parent) 
		self.setWindowTitle("QTimer demo")
		self.listFile= QListWidget() 
		self.label = QLabel('显示当前时间')
		self.startBtn = QPushButton('开始') 
		self.endBtn = QPushButton('结束') 
		layout = QGridLayout(self) 

		self.timer = QTimer(self)   # 初始化一个定时器
		self.timer.timeout.connect(self.showTime)    # 把定时器的timeout信号与槽函数showTime()连接
		
		layout.addWidget(self.label,0,0,1,2)   
		layout.addWidget(self.startBtn,1,0) 
		layout.addWidget(self.endBtn,1,1) 		
		
		self.startBtn.clicked.connect( self.startTimer) 
		self.endBtn.clicked.connect( self.endTimer)			
		self.setLayout(layout)   
		
	def showTime(self): 
		time = QDateTime.currentDateTime()  # 获取系统现在的时间
		timeDisplay = time.toString("yyyy-MM-dd hh:mm:ss dddd");   # 设置系统时间显示格式
		self.label.setText( timeDisplay )   # 在标签上显示时间

	def startTimer(self): 
        # 设置计时间隔并启动
		self.timer.start(1000)  # 时间间隔为1000ms,即1s
        # 点击开始按钮后,计时器开始计时,禁用开始按钮,不禁用结束按钮
		self.startBtn.setEnabled(False)
		self.endBtn.setEnabled(True)

	def endTimer(self): 
		self.timer.stop()
		self.startBtn.setEnabled(True)
		self.endBtn.setEnabled(False)
		
if __name__ == "__main__":  
	app = QApplication(sys.argv)  
	form = WinForm()  
	form.show()  
	sys.exit(app.exec_())
案例--弹出窗口,十秒钟消失,用于模仿程序启动界面
python
# -*- coding: utf-8 -*- 

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
 
if __name__ == '__main__':
	app = QApplication(sys.argv)
	label = QLabel("<font color=red size=128><b>Hello PyQT,窗口会在10秒后消失!</b></font>")
	label.setWindowFlags(Qt.SplashScreen|Qt.FramelessWindowHint)  # 将弹出窗口设置为无边框
	label.show()
	QTimer.singleShot(10000, app.quit)  # 设置10s后自动退出
	sys.exit(app.exec_())

QThread

QThreadQt线程类中最核心的底层类。

要使用QThread开始一个线程,可以创建它的一个子类,然后覆盖其QThread.run()函数。

python
# 创建一个自定义类,使其继承QThread,并实现run()方法
class Thread(QThread):
    def __init__(self):
        super(Thread,self).__init__()
        def run(self):
            #线程相关代码
            pass
python
# 创建线程,使用线程时可以直接得到Thread实例,调用start()函数可以启动线程,线程启动后会自动调用其实现的run方法(线程的执行函数)
thread = Thread()
thread.start()

QThread类中常用的方法和信号:

方法描述
start()启动线程
wait()阻止线程,直到满足如下条件之一:1.与此QThread对象关联的线程已完成执行(即从run()返回时),如果线程完成执行,此函数将返回True,如果线程尚未启动,此函数也返回True;2.等待时间的单位是毫秒,如果时间是ULONG_MAX(默认值),则等待,永远不会超时(线程必须从run()返回):如果等待超时,此函数将返回False
sleep()强制当前线程睡眠

QThread类中常用的信号:

信号描述
started在开始执行run()函数之前,从相关线程发射此信号
finished当程序完成业务逻辑时,从相关线程发射此信号
案例--QThread的使用

在后台定时读取数据,并把返回的数据显示在界面中

python
# -*- coding: utf-8 -*- 
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys

class MainWidget(QWidget):
	def __init__(self,parent=None):
		super(MainWidget,self).__init__(parent)
		self.setWindowTitle("QThread 例子")    
		self.thread = Worker()
		self.listFile = QListWidget()   # 创建一个多行文本框
		self.btnStart = QPushButton('开始')
		layout = QGridLayout(self)
		layout.addWidget(self.listFile,0,0,1,2)
		layout.addWidget(self.btnStart,1,1)	
		self.btnStart.clicked.connect( self.slotStart )  # 将按钮的clicked信号连接到slotStart()槽函数,单击按钮发射
		self.thread.sinOut.connect(self.slotAdd)  # 将线程的sinOut信号连接到slotAdd()槽函数
		
	def slotAdd(self,file_inf):     # slotAdd()函数负责在列表控件中动态添加字符串条目
		self.listFile.addItem(file_inf)
        
	def slotStart(self):  # slotStart()槽函数
		self.btnStart.setEnabled(False)  # 将按钮设置为禁用状态
		self.thread.start()   # 开始线程
		
class Worker(QThread):   # 定义一个线程类,当线程启动后,执行run()函数
	sinOut = pyqtSignal(str)
	def __init__(self,parent=None):
		super(Worker,self).__init__(parent)
		self.working = True
		self.num = 0
		
	def __del__(self):
		self.working = False
		self.wait()
		
	def run(self):
		while self.working == True:
			file_str = 'File index {0}'.format(self.num)
			self.num += 1	  
			self.sinOut.emit(file_str)  # 发出信号	
			self.sleep(2)  # 线程休眠2秒

if __name__ == "__main__":  			
	app = QApplication(sys.argv)
	demo = MainWidget()
	demo.show()
	sys.exit(app.exec_())

网页交互

PyQt5中通过PyQt5.QtWebKitWidgets.QWebEngineView类来使用网页控件

使用时先下载和导入相关的模块:

下载:pip install PyQt5 PyQtWebEngine

导入:from PyQt5.QtWebEngineWidgets import *

QWebEngineView类中的常用方法:

方法描述
load(QUrl url)加载指定的URL并显示
setHtml(QString &html)将网页视图的内容设置为指定的HTML内容

QWebEngineView控件使用load()函数加载一个Web页面,实际上是使用HTTP GET方法加载Web页面,这个控件既可以加载本地Web页面,也可以加载远程的外部Web页面

python
view = QWebEngineView()
view.load(QUrl('http://www.cnblogs.com/wangshuo1/')) view.show()

QWebEngineView控件还可以使用setHtml()函数加载本地的Web代码

案例--加载并显示外部的Web页面
python
# -*- coding: utf-8 -*- 
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import *
import sys

class MainWindow(QMainWindow):

	def __init__(self ):
		super(QMainWindow, self).__init__()
		self.setWindowTitle('打开外部网页例子')
		self.setGeometry(5, 30, 1355, 730)
		self.browser = QWebEngineView()
        # 加载外部页面
		self.browser.load(QUrl('http://www.cnblogs.com/wangshuo1')) # 输入一个外部的地址,进行加载访问		
		self.setCentralWidget(self.browser)

if __name__ == '__main__':
	app = QApplication(sys.argv)     
	win = MainWindow()
	win.show()
	sys.exit(app.exec_())
案例--加载并显示本地的Web页面
python
# -*- coding: utf-8 -*- 
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import *
import sys

class MainWindow(QMainWindow):

	def __init__(self ):
		super(QMainWindow, self).__init__()
		self.setWindowTitle('加载并显示本地页面例子')
		self.setGeometry(5, 30, 755, 530)
		self.browser = QWebEngineView()   
        # 加载本地页面
		url = r'D:/GithubProjects/PyQt5/Chapter05/web/index.html'  # 本地Web的路径,注意用/分隔,不是属性中的\分隔
		self.browser.load( QUrl( url ))	
		self.setCentralWidget(self.browser)

if __name__ == '__main__':
	app = QApplication(sys.argv)       
	win = MainWindow()
	win.show()
	sys.exit(app.exec_())
案例--PyQt调用JavaScript代码

通过QWebEnginePage类的runJavaScript(str, Callable)函数可以方便的实现PyQtHTML/JavaScript的双向通信,也实现了Python代码和HTML/JavaScript代码的解耦,便于开发人员进行分工协作。

PyQt对象中访问JavaScript的核心代码如下:

QWebEnginePag.runJavaScript(str, Callable)

python
# -*- coding: utf-8 -*- 
from PyQt5.QtWidgets  import QApplication , QWidget , QVBoxLayout , QPushButton
from PyQt5.QtWebEngineWidgets import QWebEngineView
import sys

# 创建一个 application实例
app = QApplication(sys.argv)  
win = QWidget()
win.setWindowTitle('Web页面中的JavaScript与 QWebEngineView交互例子')
# 创建一个垂直布局器
layout = QVBoxLayout()
win.setLayout(layout)
# 创建一个 QWebEngineView 对象
view = QWebEngineView()
view.setHtml('''
  <html>
    <head>
      <title>A Demo Page</title>

      <script language="javascript">
        // Completes the full-name control and
        // shows the submit button
        function completeAndReturnName() {
          var fname = document.getElementById('fname').value;
          var lname = document.getElementById('lname').value;
          var full = fname + ' ' + lname;

          document.getElementById('fullname').value = full;
          document.getElementById('submit-btn').style.display = 'block';

          return full;
        }
      </script>
    </head>

    <body>
      <form>
        <label for="fname">First name:</label>
        <input type="text" name="fname" id="fname"></input>
        <br />
        <label for="lname">Last name:</label>
        <input type="text" name="lname" id="lname"></input>
        <br />
        <label for="fullname">Full name:</label>
        <input disabled type="text" name="fullname" id="fullname"></input>
        <br />
        <input style="display: none;" type="submit" id="submit-btn"></input>
      </form>
    </body>
  </html>
''')

# 创建一个按钮去调用 JavaScript代码
button = QPushButton('设置全名')
def js_callback(result):
    print(result)  
def complete_name():
   view.page().runJavaScript('completeAndReturnName();', js_callback)

# 按钮连接 'complete_name'槽,当点击按钮是会触发信号
button.clicked.connect(complete_name)

# 把QWebView和button加载到layout布局中
layout.addWidget(view)
layout.addWidget(button)

# 显示窗口和运行app
win.show()
sys.exit(app.exec_())
案例--JavaScript调用PyQt代码

JavaScript调用PyQt代码,是指PyQt可以与加载的Web页面进行双向的数据交互,首先,使用QWebEngineView对象加载Web页面后,就可以获得页面中表单输入数据,在Web页面中通过JavaScript代码用户提交的数据,然后在Web界面中,JavaScript通过桥连接方式传递数据给PyQt。最后,PyQt接收页面传递的数据,经过业务处理后,还可以把处理过的数据返回给Web页面

创建QWebChannel对象:

创建QWebChannel对象,注册一个需要桥接的对象,以便Web页面的JavaScript使用,代码如下:

python
channel = QWebChannel()
myObj = MySharedObject()
channel.registerObject("bridge", myObj)
view.page().setWebChannel(channel)

创建共享数据的PyQt对象:

创建的共享对象需要继承QWidget对象或QObject对象,其代码如下:

python
class MySharedObject(QWidget):
    def __init__(self):
        super(MyShareObject, self).__init__()
        
    def _setStrValue(self, str):
        print('获得页面参数:%s'% str)
    # 需要定义对外发布的方法,需要使用pyqtProperty()函数让它暴露出来
    strValue = pyqtProperty(str, fset=_setStrValue)

Released under the MIT License.