PyQt5保姆级教程-- 从入门到精通

主要内容:

1 Qt Designer
2 PyQt5基本窗口控件(QMainWindow、Qwidget、Qlabel、QLineEdit、菜单、工具栏等)
3 PyQt5高级组件(QTableView、QListView、容器、线程等)
4 PyQt5布局管理(QBoxLayout、QGirdLayout、QFormLayout、嵌套布局等)
5 PyQt5信号与槽(事件处理、数据传递等)
6 PyQt5图形与特效(定制窗口风格、绘图、QSS与UI美化、不规则窗口、设置样式等)
7 PyQt5扩展应用(制作PyQt5安装程序、数据处理、第三方绘图库在PyQt5中的应用、UI自动化测试等)

搭建PyQt5开发环境

工具:

Python

PyQt5模块

PyCharm

在PyCharm里面安装PyQt5

pip install PyQt5 -i https://pypi.douban.com/simple

在PyCharm里面安装Qt的工具包

pip install PyQt5-tools -i https://pypi.douban.com/simple

在安装tools时,报如下错误:

1.pip install PyQt5-tools安装失败
WARNING: Ignoring invalid distribution -yqt5 (e:\venvs\pyqt5_demo1\lib\site-packages)
Installing collected packages: pyqt5, click, qt5-tools, pyqt5-plugins, pyqt5-tools
ERROR: Could not install packages due to an OSError: [WinError 5] 拒绝访问。: 'e:\\venvs\\pyqt5_demo1\\Lib\\site-packages\\PyQt5\\QtCore.pyd'
Check the permissions.

解决办法:

第一步:

pip install ...加入--userpip install --user ...即可

pip install PyQt5-tools  -i https://pypi.douban.com/simple   --user

换个思路

重启电脑,继续输入第一条命令安装

原因分析,可能占用了进程。

2.配置Qt Designer

Working directory:$FileDir$
3.配置PyUIC

Program:python的安装目录下的python.exe文件
Arguments:-m PyQt5.uic.pyuic  $FileName$ -o $FileNameWithoutExtension$.py
4.配置Pyrcc

Program:python的安装目录下的Scripts文件夹的pyrcc5.exe文件
Arguments:$FileName$ -o $FileNameWithoutExtension$_rc.py

展示效果如下:

5.ui转py的过程:

1.点击EXternal Tools里面的QTDesigner,会跳转到QT界面,

拖动组件,调整好界面,保存为first文件,它会默认生成first.ui文件

选中文件,鼠标右击,打开扩展,选择PyUIC,它会生成.py文件

将.ui文件转化为.py文件的命令行方法:

python -m PyQt5.uic.pyuic demo.ui -o demo.py
6.开发第一个基于PyQt5的桌面应用

必须使用两个类: QApplication和QWidget。都在PyQt5.QtWidgets。

第一个类表示应用程序,第二个类表示窗口

输入如下代码:

# 开发第一个基于PyQt5的桌面应用import sysfrom PyQt5.QtWidgets import QApplication,QWidgetif __name__ == '__main__':# 创建QApplication类的实例app = QApplication(sys.argv)# 创建一个窗口w = QWidget()# 设置窗口尺寸   宽度300,高度150w.resize(400,200)# 移动窗口w.move(300,300)# 设置窗口的标题w.setWindowTitle('第一个基于PyQt5的桌面应用')# 显示窗口w.show()# 进入程序的主循环,并通过exit函数确保主循环安全结束(该释放资源的一定要释放)sys.exit(app.exec_())

效果如下:

也可以在命令行运行

python 文件名.py
7.基本操作

左侧是可以选择的组件,右侧可以设定属性值,设置完成之后,可以在窗体选择预览,选择查看c++和python代码。

8.在QtDesigner中使用水平布局(Vertical Layout)

两种方式:

(1)先移组件,再布局。

放置五个按钮,让这五个按钮等宽的,水平的排列

(全部选中–>鼠标右键–>布局–>水平布局 预览)

预览:

(2)先布局,再移组件。

生成demo1.ui文件

转成demo2.py文件,转成py文件,才能在程序里面调。

生成的代码如下:

# -*- coding: utf-8 -*-# Form implementation generated from reading ui file 'demo1.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.from PyQt5 import QtCore, QtGui, QtWidgetsclass Ui_MainWindow(object):def setupUi(self, MainWindow):MainWindow.setObjectName("MainWindow")MainWindow.resize(800, 600)self.centralwidget = QtWidgets.QWidget(MainWindow)self.centralwidget.setObjectName("centralwidget")self.widget = QtWidgets.QWidget(self.centralwidget)self.widget.setGeometry(QtCore.QRect(70, 50, 651, 51))self.widget.setObjectName("widget")self.horizontalLayout = QtWidgets.QHBoxLayout(self.widget)self.horizontalLayout.setContentsMargins(0, 0, 0, 0)self.horizontalLayout.setObjectName("horizontalLayout")self.pushButton = QtWidgets.QPushButton(self.widget)self.pushButton.setObjectName("pushButton")self.horizontalLayout.addWidget(self.pushButton)self.pushButton_2 = QtWidgets.QPushButton(self.widget)self.pushButton_2.setObjectName("pushButton_2")self.horizontalLayout.addWidget(self.pushButton_2)self.pushButton_3 = QtWidgets.QPushButton(self.widget)self.pushButton_3.setObjectName("pushButton_3")self.horizontalLayout.addWidget(self.pushButton_3)self.pushButton_4 = QtWidgets.QPushButton(self.widget)self.pushButton_4.setObjectName("pushButton_4")self.horizontalLayout.addWidget(self.pushButton_4)self.widget1 = QtWidgets.QWidget(self.centralwidget)self.widget1.setGeometry(QtCore.QRect(110, 160, 578, 194))self.widget1.setObjectName("widget1")self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.widget1)self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)self.horizontalLayout_2.setObjectName("horizontalLayout_2")self.listView = QtWidgets.QListView(self.widget1)self.listView.setObjectName("listView")self.horizontalLayout_2.addWidget(self.listView)self.pushButton_5 = QtWidgets.QPushButton(self.widget1)self.pushButton_5.setObjectName("pushButton_5")self.horizontalLayout_2.addWidget(self.pushButton_5)self.checkBox = QtWidgets.QCheckBox(self.widget1)self.checkBox.setObjectName("checkBox")self.horizontalLayout_2.addWidget(self.checkBox)self.radioButton = QtWidgets.QRadioButton(self.widget1)self.radioButton.setObjectName("radioButton")self.horizontalLayout_2.addWidget(self.radioButton)MainWindow.setCentralWidget(self.centralwidget)self.menubar = QtWidgets.QMenuBar(MainWindow)self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 26))self.menubar.setObjectName("menubar")MainWindow.setMenuBar(self.menubar)self.statusbar = QtWidgets.QStatusBar(MainWindow)self.statusbar.setObjectName("statusbar")MainWindow.setStatusBar(self.statusbar)self.retranslateUi(MainWindow)QtCore.QMetaObject.connectSlotsByName(MainWindow)def retranslateUi(self, MainWindow):_translate = QtCore.QCoreApplication.translateMainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))self.pushButton.setText(_translate("MainWindow", "Button1"))self.pushButton_2.setText(_translate("MainWindow", "Button2"))self.pushButton_3.setText(_translate("MainWindow", "Button3"))self.pushButton_4.setText(_translate("MainWindow", "Button4"))self.pushButton_5.setText(_translate("MainWindow", "PushButton"))self.checkBox.setText(_translate("MainWindow", "CheckBox"))self.radioButton.setText(_translate("MainWindow", "RadioButton"))

如何在程序里面调用,先新建一个Run_demo1.py文件

代码如下:

import sys
import demo1from PyQt5.QtWidgets import QApplication,QMainWindowif __name__ == '__main__':# 只有直接运行这个脚本,才会往下执行# 别的脚本文件执行,不会调用这个条件句# 实例化,传参app = QApplication(sys.argv)# 创建对象mainWindow = QMainWindow()# 创建ui,引用demo1文件中的Ui_MainWindow类ui = demo1.Ui_MainWindow()# 调用Ui_MainWindow类的setupUi,创建初始组件ui.setupUi(mainWindow)# 创建窗口mainWindow.show()# 进入程序的主循环,并通过exit函数确保主循环安全结束(该释放资源的一定要释放)sys.exit(app.exec_())

运行:

弹出如下窗口:

此时出现了一个小问题:

如何解决: (将此目录生成源代码目录)

设置完成之后,等待加载完成,导入文件名底下的红线消失

9.在QtDesigner中使用垂直布局(Horizontal Layout)

和水平布局的操作类似,也有两种布局方式:

(1) 先移动组件,再布局

(2) 先布局,再移动组件

点击保存,生成垂直布局文件demo2.ui

右键demo2.ui,生成demo2.py文件

demo2.py的代码如下:

# -*- coding: utf-8 -*-# Form implementation generated from reading ui file 'demo2.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.from PyQt5 import QtCore, QtGui, QtWidgetsclass Ui_MainWindow(object):def setupUi(self, MainWindow):MainWindow.setObjectName("MainWindow")MainWindow.resize(800, 600)self.centralwidget = QtWidgets.QWidget(MainWindow)self.centralwidget.setObjectName("centralwidget")self.verticalLayoutWidget = QtWidgets.QWidget(self.centralwidget)self.verticalLayoutWidget.setGeometry(QtCore.QRect(180, 150, 441, 371))self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)self.verticalLayout_2.setObjectName("verticalLayout_2")self.label = QtWidgets.QLabel(self.verticalLayoutWidget)self.label.setObjectName("label")self.verticalLayout_2.addWidget(self.label)self.pushButton_6 = QtWidgets.QPushButton(self.verticalLayoutWidget)self.pushButton_6.setObjectName("pushButton_6")self.verticalLayout_2.addWidget(self.pushButton_6)self.pushButton_5 = QtWidgets.QPushButton(self.verticalLayoutWidget)self.pushButton_5.setObjectName("pushButton_5")self.verticalLayout_2.addWidget(self.pushButton_5)self.pushButton_4 = QtWidgets.QPushButton(self.verticalLayoutWidget)self.pushButton_4.setObjectName("pushButton_4")self.verticalLayout_2.addWidget(self.pushButton_4)self.checkBox = QtWidgets.QCheckBox(self.verticalLayoutWidget)self.checkBox.setObjectName("checkBox")self.verticalLayout_2.addWidget(self.checkBox)self.widget = QtWidgets.QWidget(self.centralwidget)self.widget.setGeometry(QtCore.QRect(40, 40, 95, 121))self.widget.setObjectName("widget")self.verticalLayout = QtWidgets.QVBoxLayout(self.widget)self.verticalLayout.setContentsMargins(0, 0, 0, 0)self.verticalLayout.setObjectName("verticalLayout")self.pushButton = QtWidgets.QPushButton(self.widget)self.pushButton.setObjectName("pushButton")self.verticalLayout.addWidget(self.pushButton)self.pushButton_2 = QtWidgets.QPushButton(self.widget)self.pushButton_2.setObjectName("pushButton_2")self.verticalLayout.addWidget(self.pushButton_2)self.pushButton_3 = QtWidgets.QPushButton(self.widget)self.pushButton_3.setObjectName("pushButton_3")self.verticalLayout.addWidget(self.pushButton_3)MainWindow.setCentralWidget(self.centralwidget)self.menubar = QtWidgets.QMenuBar(MainWindow)self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 26))self.menubar.setObjectName("menubar")MainWindow.setMenuBar(self.menubar)self.statusbar = QtWidgets.QStatusBar(MainWindow)self.statusbar.setObjectName("statusbar")MainWindow.setStatusBar(self.statusbar)self.retranslateUi(MainWindow)QtCore.QMetaObject.connectSlotsByName(MainWindow)def retranslateUi(self, MainWindow):_translate = QtCore.QCoreApplication.translateMainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))self.label.setText(_translate("MainWindow", "TextLabel"))self.pushButton_6.setText(_translate("MainWindow", "PushButton"))self.pushButton_5.setText(_translate("MainWindow", "PushButton"))self.pushButton_4.setText(_translate("MainWindow", "PushButton"))self.checkBox.setText(_translate("MainWindow", "CheckBox"))self.pushButton.setText(_translate("MainWindow", "PushButton"))self.pushButton_2.setText(_translate("MainWindow", "PushButton"))self.pushButton_3.setText(_translate("MainWindow", "PushButton"))

在python程序里面调用,新建Run_demo2.py文件

代码如下:

import sys
import demo2from PyQt5.QtWidgets import QApplication,QMainWindowif __name__ == '__main__':# 只有直接运行这个脚本,才会往下执行# 别的脚本文件执行,不会调用这个条件句# 实例化,传参app = QApplication(sys.argv)# 创建对象mainWindow = QMainWindow()# 创建ui,引用demo1文件中的Ui_MainWindow类ui = demo2.Ui_MainWindow()# 调用Ui_MainWindow类的setupUi,创建初始组件ui.setupUi(mainWindow)# 创建窗口mainWindow.show()# 进入程序的主循环,并通过exit函数确保主循环安全结束(该释放资源的一定要释放)sys.exit(app.exec_())

运行程序:

10.在QtDesigner里面同时创建垂直布局和水平布局

新建一个 main window,点击 创建

在布局的时候,windows里面,可以通过ctrl+上下左右进行微调。

文件保存,命名为demo3.ui文件,同样用拓展工具,生成demo3.py文件。

同样,新建运行文件Run_demo3.py文件,代码如下:

import sys
import demo3from PyQt5.QtWidgets import QApplication,QMainWindowif __name__ == '__main__':# 只有直接运行这个脚本,才会往下执行# 别的脚本文件执行,不会调用这个条件句# 实例化,传参app = QApplication(sys.argv)# 创建对象mainWindow = QMainWindow()# 创建ui,引用demo1文件中的Ui_MainWindow类ui = demo3.Ui_MainWindow()# 调用Ui_MainWindow类的setupUi,创建初始组件ui.setupUi(mainWindow)# 创建窗口mainWindow.show()# 进入程序的主循环,并通过exit函数确保主循环安全结束(该释放资源的一定要释放)sys.exit(app.exec_())

运行代码,结果如下:

11.在QtDesigner中同时使用栅格布局(Grid Layout)

拖放四个按钮之后,选中栅格布局

选中之后,效果如下:

拖拽边角,可以放大:

练习:利用栅格布局实现计算器数字区域

拖动button键调整好位置,全选之后选中布局,再选栅格布局

点击栅格之后,效果如下:

保存,生成demo4.ui文件

同样进行上述操作,转成demo4.py文件,新建Run_demo4.py文件,代码如下:

import sys
import demo4from PyQt5.QtWidgets import QApplication,QMainWindowif __name__ == '__main__':# 只有直接运行这个脚本,才会往下执行# 别的脚本文件执行,不会调用这个条件句# 实例化,传参app = QApplication(sys.argv)# 创建对象mainWindow = QMainWindow()# 创建ui,引用demo1文件中的Ui_MainWindow类ui = demo4.Ui_MainWindow()# 调用Ui_MainWindow类的setupUi,创建初始组件ui.setupUi(mainWindow)# 创建窗口mainWindow.show()# 进入程序的主循环,并通过exit函数确保主循环安全结束(该释放资源的一定要释放)sys.exit(app.exec_())

效果如下:

栅格布局的注意点:摆放控件要尽可能的整齐,这样系统才会正确的识别。

栅格布局和水平布局,垂直布局一样,可以后期添加控件。

12.向栅格布局中拖动控件

13.在QtDesigner中使用表单布局(Form Layout)

新建一个 main window,点击 创建

选择需要的控件,进行如下操作:

调整好布局,保存文件为demo5.ui

利用pyUIC插件,生成python代码调试

创建Run_demo5.py文件,执行代码如下:

import sys
import demo5from PyQt5.QtWidgets import QApplication,QMainWindowif __name__ == '__main__':# 只有直接运行这个脚本,才会往下执行# 别的脚本文件执行,不会调用这个条件句# 实例化,传参app = QApplication(sys.argv)# 创建对象mainWindow = QMainWindow()# 创建ui,引用demo1文件中的Ui_MainWindow类ui = demo5.Ui_MainWindow()# 调用Ui_MainWindow类的setupUi,创建初始组件ui.setupUi(mainWindow)# 创建窗口mainWindow.show()# 进入程序的主循环,并通过exit函数确保主循环安全结束(该释放资源的一定要释放)sys.exit(app.exec_())

效果如下:

14.在容器中完成布局

跟上面一样,新建一个MainWindow,添加对应的组件,鼠标右键点击,变形为对应的容器。

同理,生成demo6.py文件,新建Run_demo6文档,添加代码

import sys
import demo6from PyQt5.QtWidgets import QApplication,QMainWindowif __name__ == '__main__':# 只有直接运行这个脚本,才会往下执行# 别的脚本文件执行,不会调用这个条件句# 实例化,传参app = QApplication(sys.argv)# 创建对象mainWindow = QMainWindow()# 创建ui,引用demo1文件中的Ui_MainWindow类ui = demo6.Ui_MainWindow()# 调用Ui_MainWindow类的setupUi,创建初始组件ui.setupUi(mainWindow)# 创建窗口mainWindow.show()# 进入程序的主循环,并通过exit函数确保主循环安全结束(该释放资源的一定要释放)sys.exit(app.exec_())

运行程序

15.在QtDesigner中使用绝对布局

跟上面一样,新建一个MainWindow,添加对应的组件,

同理,生成demo7.py文件,新建Run_demo7文档,添加代码(代码如上,略作修改),PyCharm里运行如下:

15.在QtDesigner中使用分割线与间隔

跟上面一样,新建一个MainWindow,

新建4个按钮,设置水平间隔,新建3个按钮,设置垂直间隔

在A2和A3之间设立分割线,在B2和B3之间设立分割线

保存文件为demo8.ui ,转为demo8.py代码,新建Run_demo8.py,添加代码(代码如上,略作修改),PyCharm里运行如下:

16.布局的最大尺寸和最小尺寸

默认状态下,它的尺寸可以自由调节,跟上面一样,新建一个MainWindow,

可以看到,原本这个bushButton控件最小宽高可以到0,最大宽高可以到1677215

通过改变右侧栏的值,就可以设置它不小于多少,不大于多少。

16.尺寸策略(sizePolicy)

对于大多数控件来说,sizeHint(期望尺寸)是只可读的,也就是说,你布局的时候不管拖拽多大,最后输出的还是默认值

读取pushButton的期望尺寸:

self.pushButton.sizeHint().width()
self.pushButton.sizeHint().height()

即可以看到,一个pushButton的期望尺寸,宽是41,高度是28

在demo7里进行上面操作,还是得到一样的数值。

同理,也可以进行读取其他控件的操作,比如读取textBrowser的宽高,代码如下:

self.c.sizeHint().width()
self.textBrowser.sizeHint().height()

效果如下:

即可以看到:控件textBrowser的默认宽高分别为256和192。

同样,也可以看最小的期望尺寸,以pushButton为例,其代码如下:

self.pushButton.minimumSizeHint().width()
self.pushButton.minimumSizeHint().height()

还是以demo7.py测试

可以看到,对于大部分控件来说,它的期望尺寸和最小期望尺寸是一样的

为何使用尺寸策略:

就是因为拓展的组件无论如何拖拽大小,经过布局设置之后,会回到默认的大小,为了让布局更有个性,采用尺寸策略,可以改变组件的期望尺寸。如图:

练习,左侧放树,构造分栏效果

保存文档为demo9.ui,转为demo9.py代码,新建Run_demo9.py,添加代码(代码如上,略作修改),PyCharm里运行如下:

17.在QtDesigner里面设置控件之间的伙伴关系

即控件关联之后,可以通过一个控件来控制另外一个控件

新建一个MainWindow,布局如下,保存为demo10.ui

接着:

如上图所示,水平布局后面的“H”为热键 ,Ctrl +1 为快捷键

​ 垂直布局后面的“V”为热键 ,Ctrl +2 为快捷键

热键:只有在这个菜单显示时,按“H”时,才会起作用。菜单关闭时,按“H”不起作用。“V”同理。

然后给demo10.ui文件的lable添加热键:

给姓名添加热键成:姓名(&A):

给年龄添加热键成:年龄(&B):

给邮箱添加热键成:邮箱(&C):

然后打开编辑伙伴,按住鼠标左键,选中lable指向Line Edit

然后选择编辑窗口部件,会切回到正常的部件

保存文件为demo10.ui ,转为demo10.py代码,新建Run_demo10.py,添加代码(代码如上,略作修改),PyCharm里运行如下:

再添加三个lable试一下效果,删除掉原来的demo10.py文件,用新保存的demo10.ui去生成新的demo10.py文件,点击运行查看效果

果然,按住alt+a,alt+b,alt+c,alt+d,alt+e.alt+f分别在右边对应的的Line Edit里面有焦点光标。

拓展:

18.如何修改控件的Tab顺序

新建一个MainWindow,布局如下,在Edit里面,选中 编辑 Tab顺序,在控件前端就会出现序号,这个序号就是顺序

也可以选中从这里开始或者重新开始,依次点击形成顺序。

接下来选中统一的 Line Edit来演示

保存文档为demo11.ui,转为demo11.py代码,新建Run_demo11.py,添加代码(代码如上,略作修改),PyCharm里运行如下:

按Tab 键,焦点光标就会按照指定的顺序在Line Edit内跳转

19.在QtDesigner中完成信号与槽的设置

信号(signal)与槽(slot)是Qt的核心机制,由于PyQt忠实的继承了Qt的所有特性,所有信号与槽也是PyQt的核心机制。

信号:是由对象或控件发射出去的消息。可以理解为按钮的单击事件。

当单击按钮时,按钮就会向外部发送单击的消息,这些发送出去的信号需要一些代码来拦截,这些代码就是槽

槽本质上是一个函数或者方法,信号可以理解为事件,槽可以理解为事件函数

信号与槽的设置:就是需要将信号和槽绑定

一个信号可以和多个槽绑定,一个槽可以拦截多个信号。

信号和槽绑定有两种方式,一种是用QtDesigner进行绑定,一种是在代码中进行绑定

(1)用QtDesigner进行信号和槽绑定

需求:单机按钮,关闭窗口

新建一个MainWindow,拖拽一个pashButton按钮,修改文本为“关闭窗口”

在Edit里选择编辑信号/槽,点击pashButton按钮向外拖拽,

在Edit里选择编辑信号/槽,点击pashButton按钮向外拖拽,松开鼠标,左栏选择clicked(),勾选左下角“显示从QWidget”继承信号和槽,右栏选择close(),然后点击右下角ok.

在Edit里面选择“编辑窗口部件”,对布局页面进行恢复。

在“窗体”里选择“预览于”,选择“Windows风格”

此时点击页面的“关闭窗口”,则页面就会关闭

练习

添加两个CheckBox进行如下操作:

给第一个CheckBox进行信号与槽的绑定

给第二个CheckBox进行信号与槽的绑定

在Edit里面选择"编辑窗口部件"进行恢复主窗口

恢复完成后,窗口如下:

预览效果如下:

取消勾选check box的选项,下面的line Edit视角效果也会相应的变换。

保存文档为demo12.ui,转为demo12.py代码,新建Run_demo12.py,添加代码(代码如上,略作修改),PyCharm里运行如下:

拓展:

(2)用代码完成关闭主窗口

​ 见第23节

20 在QtDesigner中为窗口添加菜单和工具栏

一个窗口,应该拥有菜单栏,工具栏,状态栏

新建一个MainWindow,添加菜单栏,添加完成之后,也可以右键点击,选择移除,同理添加工具栏。

给菜单栏添加内容:

在”窗体“里选择预览,效果如下:

在菜单和工具条里面如何添加按钮?

不管是菜单还是工具条的按钮,是一个action的动作,添加步骤如下:

在"视图"里,选择动作编辑器

两个菜单自动生成两个动作,双击可用设置动作

点击"ok"之后,主窗口变化如下:

保存文档为demo13.ui,转为demo13.py代码,新建Run_demo13.py,添加代码(代码如上,略作修改),PyCharm里运行如下:

21 创建主窗口

主窗口类型,有三种窗口

窗口类型 说明
QMainWindow 可以包含菜单栏、工具栏、状态栏和标题栏,是最常见的窗口形式
QDialog 是对话窗口的基类。没有菜单栏、工具栏、状态栏
QWidget 不确定窗口的用途,就使用QWidget

如下图所示,新建一个controls文件夹,在controls里面新建images文件夹用来装图片,在controls里面新建

FirstMainWin.py文件。

在FirstMainWin.py文件中,添加代码如下:

# 第一个主窗口
# 把所有和UI有关的代码都放在一个类里面,创建窗口只要创建类的实例就可以了import sys# 从PyQt里面创建窗口和应用
from PyQt5.QtWidgets import QMainWindow,QApplication
# 用来添加图标
from PyQt5.QtGui import QIcon# 定义一个类,这个类从QMainWindow里面继承class FristMainWin(QMainWindow):# 初始化def __init__(self,parent=None):super(FristMainWin,self).__init__(parent)# 设置主窗口的标题self.setWindowTitle('第一个主窗口应用')# 设置窗口的尺寸self.resize(400,300)# 获得状态栏self.status = self.statusBar()# 在状态栏上,设置消息的状态时间5000msself.status.showMessage('只存在5秒的消息',5000)# 防止别的脚本调用,只有自己单独运行,才会调用下面代码
if __name__ == '__main__':# 创建app实例,并传入参数app =  QApplication(sys.argv)# 设置图标app.setWindowIcon(QIcon('images/horse.jpg'))# 创建对象main = FristMainWin()# 创建窗口main.show()# 进入程序的主循环,并通过exit函数确保主循环安全结束(该释放资源的一定要释放)sys.exit(app.exec_())

运行代码,效果如下:

五秒之后,页面效果如下:

22.让主窗口居中显示

计算窗口的左上角的坐标

移动左上角的坐标,带动整个窗口的移动。

左上角的横坐标就是窗口的左边距,左上角的纵坐标就是窗口的上边距到顶部的值

新建CenterForm.py文件,执行代码:

# 让主窗口居中显示# 通过QDesktopWidget类相应的API可以得到整个屏幕的尺寸
# 通过move方法移动窗口
import sys# 从PyQt里面创建窗口和应用
from PyQt5.QtWidgets import QDesktopWidget,QMainWindow,QApplication
# 用来添加图标
from PyQt5.QtGui import QIcon# 定义一个类,这个类从QMainWindow里面继承class CenterForm(QMainWindow):# 初始化def __init__(self,parent=None):super(CenterForm,self).__init__(parent)# 设置主窗口的标题self.setWindowTitle('让窗口居中')# 设置窗口的尺寸self.resize(400,300)# 添加center方法,作用就是让窗口居中def center(self):# 创建实例,获得屏幕对象,得到屏幕的坐标系screen = QDesktopWidget().screenGeometry()# 得到窗口的坐标系size = self.geometry()# 获取屏幕的宽度、高度# 窗口左边缘的坐标等于(屏幕的宽度-窗口的宽度)/2newLeft = (screen.width()-size.width()) / 2# 屏幕上边缘的坐标等于(屏幕的高度-窗口的高度) / 2newTop = (screen.height() - size.height()) / 2# 移动窗口self.move(newLeft,newTop)#  获得状态栏# self.status = self.statusBar()## # 在状态栏上,设置消息的状态时间5000ms# self.status.showMessage('只存在5秒的消息',5000)# 防止别的脚本调用,只有自己单独运行,才会调用下面代码
if __name__ == '__main__':# 创建app实例,并传入参数app =  QApplication(sys.argv)# 设置图标# app.setWindowIcon(QIcon('images/001.jpg'))# 创建对象main =CenterForm()# 创建窗口main.show()# 进入程序的主循环,并通过exit函数确保主循环安全结束(该释放资源的一定要释放)sys.exit(app.exec_())

效果展示:

23.如何退出应用程序

可以通过关闭主窗口,由于整个程序只有一个窗口,关闭主窗口之后,应用程序就会退出,之前在第19节演示过

换个思路,通过代码,在窗口上添加一个pashButton,调用QApplication里面的click()方法,来实现退出应用程序,关闭所有窗口

在controls文件夹里,新建QuitApplication.py文件,添加下列代码

# 退出应用程序
# 用到了水平布局,引入QHBoxLayout
# 需要一个控件,引入了QWidget
# 需要butoon,引入了QPushButton
import sys
from PyQt5.QtWidgets import QHBoxLayout,QMainWindow,QApplication,QPushButton,QWidget
# 用来添加图标
from PyQt5.QtGui import QIconclass QuitApplication(QMainWindow):# 初始化def __init__(self):super(QuitApplication,self).__init__()# 设计窗口的尺寸self.resize(300,120)# 设置主窗口的标题self.setWindowTitle('退出应用程序')# 添加Button# 创建全局对象self.button1self.button1 = QPushButton('退出应用程序')# 发送单击信号,执行对应的方法  (将信息与槽关联)self.button1.clicked.connect(self.onClick_Button)# 创建水平布局layout = QHBoxLayout()# 将组件加到水平局部里面layout.addWidget(self.button1)# 放置一个主框架mainFrame = QWidget()# 在主框架内添加水平布局mainFrame.setLayout(layout)# 把主框架放在窗口上self.setCentralWidget(mainFrame)# 按钮的单击事件的方法(自定义的槽)def onClick_Button(self):sender = self.sender()print(sender.text() + '按钮被按下')# 得到实例app = QApplication.instance()# 退出应用程序app.quit()# 防止别的脚本调用,只有自己单独运行,才会调用下面代码
if __name__ == '__main__':# 创建app实例,并传入参数app =  QApplication(sys.argv)# 设置图标app.setWindowIcon(QIcon('images/001.jpg'))# 创建对象main = QuitApplication()# 创建窗口main.show()# 进入程序的主循环,并通过exit函数确保主循环安全结束(该释放资源的一定要释放)sys.exit(app.exec_())

运行代码,效果如下:

点击“退出应用程序”

24.屏幕坐标系

在controls文件夹里,新建ScreenGeometry.py文件,添加下列代码

# 屏幕坐标系
# 它是以屏幕左上角为原点,划分的坐标系# 下面演示用面向过程的方式进行演示  (面向对象的方式需要创建类,创建方法)import sys
from PyQt5.QtWidgets import QHBoxLayout,QMainWindow,QApplication,QPushButton,QWidget# 创建实例
app = QApplication(sys.argv)
# 创建窗口
widget = QWidget()
# 在窗口里放button
btn = QPushButton(widget)
# 在button里面更改文本
btn.setText("按钮")# 添加点击事件,让鼠标点击button后,打印出“onclick”
def onClick_Button():print("第一种方式获取各个值")# 窗口离屏幕原点到y轴的距离print("widget.x() = %d" % widget.x())   # 600 (以屏幕为原点的窗口横坐标)# 窗口离屏幕原点到x轴的距离print("widget.y() = %d" % widget.y())    # 200  (以屏幕为原点的窗口纵坐标,不包含标题栏)# 窗口本身的宽度print("widget.width()=%d" % widget.width())    # 300 (窗口宽度)# 窗口本身的高度print("widget.height()= %d" % widget.height())    # 240  (工作区高度)print("第二种方式获取各个值")# 窗口离屏幕原点到y轴的距离print("widget.geometry().x() = %d" % widget.geometry().x())  # 601   (以屏幕为原点的窗口横坐标)# 窗口离屏幕原点到x轴的距离print("widget.geometry().y() = %d" % widget.geometry().y())  # 238    (以屏幕为原点的窗口纵坐标,包含标题栏)# 窗口本身的宽度print("widget.geometry().width()=%d" % widget.geometry().width())  # 300    (窗口宽度)# 窗口本身的高度print("widget.geometry().height()= %d" % widget.geometry().height())  # 240    (工作区高度)print("第三种方式获取各个值")# 窗口离屏幕原点到y轴的距离print("widget.frameGeometry().x() = %d" % widget.frameGeometry().x())    # 600  (以屏幕为原点的窗口横坐标)# 窗口离屏幕原点到x轴的距离print("widget.frameGeometry().y() = %d" % widget.frameGeometry().y())    # 200    (以屏幕为原点的窗口纵坐标,不包含标题栏)# 窗口本身的宽度print("widget.frameGeometry().width()=%d" % widget.frameGeometry().width())    # 302   (窗口宽度)# 窗口本身的高度print("widget.frameGeometry().height()= %d" % widget.frameGeometry().height())    # 279  (窗口高度,包含标题栏)# 将点击事件与槽绑定
btn.clicked.connect(onClick_Button)# 移动button到窗口内的相应位置
btn.move(24,52)# 设置窗口的尺寸
widget.resize(300,240)  # 设置工作区的尺寸# 移动窗口到屏幕的相应位置
widget.move(600,200)# 设置窗口的标题
widget.setWindowTitle('屏幕坐标系')# 创建窗口
widget.show()# 进入程序的主循环,并通过exit函数确保主循环安全结束(该释放资源的一定要释放)
# 如果不添加下行代码,运行程序会闪退
sys.exit(app.exec_())

运行代码,效果如下:

点击窗口里面的“按钮”,效果如下:

分析代码:

有些许误差是因为在windows下窗体有边框,在mac下窗体无边框。

25.设置窗口和应用程序图标

在controls文件夹里,新建IconForm.py文件,执行代码:

# 设置窗口和应用程序图标# 窗口的setWindowIcon方法设置窗口的图标,只在Windows和linux中可用,mac不可用import sys# 从PyQt里面创建窗口和应用
from PyQt5.QtWidgets import QMainWindow,QApplication
# 用来添加图标
from PyQt5.QtGui import QIcon# 定义一个类,这个类从QMainWindow里面继承class IconForm(QMainWindow):# 初始化def __init__(self,parent=None):super(IconForm,self).__init__(parent)self.initUI()# 规范代码,初始化直接写在一个方法里def initUI(self):# 设置坐标系,可用同时设置窗口的尺寸和位置self.setGeometry(400,400,250,450)# 设置主窗口的标题self.setWindowTitle('设置窗口图标')# 设置窗口图标self.setWindowIcon(QIcon('./images/001.jpg'))# self.setWindowIcon(QIcon('/images/3.ico'))   这行代码失效,原因:图片路径表示问题# # 设置窗口的尺寸# self.resize(400,300)# 获得状态栏# self.status = self.statusBar()## # 在状态栏上,设置消息的状态时间5000ms# self.status.showMessage('只存在5秒的消息',5000)# 防止别的脚本调用,只有自己单独运行,才会调用下面代码
if __name__ == '__main__':# 创建app实例,并传入参数app =  QApplication(sys.argv)# QApplication中的setWindowIcon方法用于设置主窗口的图标和应用程序图标,但调用了窗口的setWinodowIcon方法# QApplication中的setWindowIcon方法就只能用于设置应用程序图标了# 设置图标# app.setWindowIcon(QIcon('images/horse.jpg'))# 创建对象main = IconForm()# 创建窗口main.show()# 进入程序的主循环,并通过exit函数确保主循环安全结束(该释放资源的一定要释放)sys.exit(app.exec_())

效果如下:

26.显示控件的提示信息

在controls文件夹里,新建Tooltip.py文件,执行代码:

# 显示控件的提示信息# 需要用到 QToolTipimport sys
from PyQt5.QtWidgets import  QHBoxLayout,QMainWindow,QApplication,QToolTip,QPushButton,QWidget
# 提示信息需要设置字体
from PyQt5.QtGui import QFontclass TooltipForm(QMainWindow):def __init__(self):super().__init__()# 调用初始化ui的一个方法self.initUI()# 编写初始化UI的方法def initUI(self):# 设置字体和字号QToolTip.setFont(QFont('SansSerif',12))# 给窗口设置提示,这个方法支持富文本self.setToolTip('今天是个<b>好日子</b>')# 设置窗口的位置和尺寸self.setGeometry(300,300,200,200)# 设置窗口的标题self.setWindowTitle('设置控件提示消息')# 防止别的脚本调用,只有自己单独运行时,才会调用下面代码
if __name__ == '__main__':# 创建app实例,并传入参数app= QApplication(sys.argv)# 创建对象main = TooltipForm()# 创建窗口main.show()# 进入程序的主循环,并通过exit函数,确保主循环安全结束(该释放资源的释放资源)sys.exit(app.exec_())

效果如下:

拓展,给窗口添加一个按钮,并显示提示信息

# 显示控件的提示信息# 需要用到 QToolTipimport sys
from PyQt5.QtWidgets import  QHBoxLayout,QMainWindow,QApplication,QToolTip,QPushButton,QWidget
# 提示信息需要设置字体
from PyQt5.QtGui import QFontclass TooltipForm(QMainWindow):def __init__(self):super().__init__()# 调用初始化ui的一个方法self.initUI()# 编写初始化UI的方法def initUI(self):# 设置字体和字号QToolTip.setFont(QFont('SansSerif',12))# 给窗口设置提示,这个方法支持富文本self.setToolTip('今天是个<b>好日子</b>')# 设置窗口的位置和尺寸self.setGeometry(300,300,200,200)# 设置窗口的标题self.setWindowTitle('设置控件提示消息')# 添加butoon按钮并设置提示信息# 添加Button# 创建全局对象self.button1self.button1 = QPushButton('我的按钮')# 设置按钮提示self.button1.setToolTip('这是按钮的提示信息')# 发送单击信号,执行对应的方法  (将信息与槽关联)self.button1.clicked.connect(self.onClick_Button)# 创建水平布局layout = QHBoxLayout()# 将组件加到水平局部里面layout.addWidget(self.button1)# 放置一个主框架mainFrame = QWidget()# 在主框架内添加水平布局mainFrame.setLayout(layout)# 把主框架放在窗口上self.setCentralWidget(mainFrame)# 按钮的单击事件的方法(自定义的槽)def onClick_Button(self):sender = self.sender()print(sender.text() + '按钮被按下')# 得到实例app = QApplication.instance()# 退出应用程序app.quit()# 防止别的脚本调用,只有自己单独运行时,才会调用下面代码
if __name__ == '__main__':# 创建app实例,并传入参数app= QApplication(sys.argv)# 创建对象main = TooltipForm()# 创建窗口main.show()# 进入程序的主循环,并通过exit函数,确保主循环安全结束(该释放资源的释放资源)sys.exit(app.exec_())

效果如下:

27.QLabel控件的基本用法

PyQt5常用控件之一,QLable控件,常用来展示文本信息

控件方法 说明
setAlignment() 设置文本的对齐方式
setIndent() 设置文本缩进
text() 获取文本内容
setBuddy() 设置伙伴关系
setText() 设置文本内容
selectedText() 返回所选择的字符
setWordWrap() 设置是否允许换行

QLabel常用的信号(事件):
1.当鼠标划过QLabel控件时触发:linkHovered

2.当鼠标单击QLabel控件时触发:linkActivated

在controls文件夹里,新建QLabelDemo.py文件,执行代码:

# QLabel控件的基本用法import sys
# 导入QLabel模块  QVBoxLayout垂直布局  (QHBoxLayout 水平布局)
from PyQt5.QtWidgets import QVBoxLayout,QMainWindow,QApplication,QLabel,QWidget
# 导入调制板,调制QLabel背景色
# 导入显示图片包QPixmap
from PyQt5.QtGui import QPixmap,QPalette
# 导入一些Qt的常量
from PyQt5.QtCore import Qt# 编写一个类,从QWidget中继承
class QLabelDemo(QWidget):def __init__(self):super().__init__()# 调用初始化UI的一个方法self.initUI()# 规范代码,初始化UI直接写在一个方法里def initUI(self):# 创建四个label控件label1 = QLabel(self)label2 = QLabel(self)label3 = QLabel(self)label4 = QLabel(self)# 给label1设置文本,支持html的标签label1.setText("<font color=purpel>这是一个文本标签.</font>")# 用调试板自动填充背景label1.setAutoFillBackground(True)# 创建调试板palette = QPalette()# 给调试板设置背景色palette.setColor(QPalette.Window,Qt.blue)# 对label1使用调试板label1.setPalette(palette)# 让label1居中对齐label1.setAlignment(Qt.AlignCenter)# 给label2设置<a>标签label2.setText("<a href='#'>欢迎使用Python GUI程序</a>")  # 可以在a标签里触发事件或者跳转网页 二者选其一# 给label3设置文本居中label3.setAlignment(Qt.AlignCenter)# 给label3设置提示文本label3.setToolTip('这是一个图片标签')# 让label3显示图片label3.setPixmap(QPixmap("./images/4.jpg"))   # 同级目录写法./images# 给label4设置文本内容label4.setText("<a href='https://www.baidu.com/'>打开百度</a>")  # setText里面的内容要用双引号,单引号会报错# 让label4打开链接# 如果设为True,用浏览器打开网页,如果设为False,调用槽函数label4.setOpenExternalLinks(True)# 让label4的文本右对齐label4.setAlignment(Qt.AlignRight)# 给label4设置提示文本label4.setToolTip('这是一个超链接')# 创建一个垂直布局vbox = QVBoxLayout()# 分别把这四个控件放到这个布局里面           布局函数 addWidgetvbox.addWidget(label1)vbox.addWidget(label2)vbox.addWidget(label3)vbox.addWidget(label4)# 将信号与槽绑定label2.linkHovered.connect(self.linkHovered)label4.linkActivated.connect(self.linkClicked)# 设置布局self.setLayout(vbox)self.setWindowTitle('QLabel控件演示')# 设置标题# 槽有两个方法 1.滑过  2.单击def linkHovered(self):print("当鼠标滑过label2标签时,触发事件")def linkClicked(self):print("当鼠标单击label4标签时,触发事件")# 防止别的脚本调用,只有自己单独运行,才会调用下面代码
if __name__ == '__main__':# 创建app实例,并传入参数app =  QApplication(sys.argv)# 设置图标# app.setWindowIcon(QIcon('images/001.jpg'))# 创建对象main = QLabelDemo()# 创建窗口main.show()# 进入程序的主循环,并通过exit函数确保主循环安全结束(该释放资源的一定要释放)sys.exit(app.exec_())

效果展示:

注意:调整好图片的尺寸,防止它跳出屏幕外

28.如何设置QLabel控件和其他控件的伙伴关系

在controls文件夹里,新建QLabelBuddy.py文件,执行代码:

# QLabel与伙伴控件
# 1.通过setBuddy设置伙伴关系
# 2.通过栅格布局来完成手动布局,依靠
# mainLayout.addWidget(控件对象,rowIndex,columnIndex,row,column)   (行索引,索引,占用多少行,占用多少列)import sys
from PyQt5.QtWidgets import *class QLabelBuddy(QDialog):def __init__(self):super().__init__()self.initUI()# 规范代码,初始化直接写在一个方法里def initUI(self):# 设置主窗口的标题self.setWindowTitle('QLabel与伙伴控件')# 创建nameLabel控件#添加热键   添加热键的方法& + 英文字母  ,后面的英文字母就变成了热键。在可视化窗口里通过 "Alt" + 英文字母 就可以起作用nameLabel =QLabel('&Name',self)# 创建QLineEdit控件nameLineEdit = QLineEdit(self)# 把nameLabel和nameLineEdit设置伙伴关系nameLabel.setBuddy(nameLineEdit)# 创建PasswordQLabel控件, 并添加热键passwordLabel = QLabel('&Password',self)# 创建PasswordLineEdit控件passwordLineEdit = QLineEdit(self)# 把passwordLabel和passwordLineEdit设置成伙伴关系passwordLabel.setBuddy(passwordLineEdit)# 创建两个按钮,一个上面写OK,一个上面写CancelbtnOK = QPushButton('&OK')btnCancel = QPushButton('&Cancel')# 使用栅格布局mainLayout = QGridLayout(self)# 将nameLabel控件放到布局里面    第一行第一列mainLayout.addWidget(nameLabel,0,0)# 将nameLineEdit控件放到布局里面  第一行第二列,占用一行两列mainLayout.addWidget(nameLineEdit,0,1,1,2)# 将passwordLabel控件放到布局里面  第二行第一列mainLayout.addWidget(passwordLabel,1,0)# 将passwordLineEdit控件放到布局里面 第二行第一列,占用一行两列mainLayout.addWidget(passwordLineEdit,1,1,1,2)# 经过上面操作,此时有两行,每行有三列# 放置按钮  第三行第二列mainLayout.addWidget(btnOK,2,1)# 放置按钮    第三行第三列mainLayout.addWidget(btnCancel,2,2)# 防止别的脚本调用,只有自己单独运行时,才会调用下面代码
if __name__ == '__main__':# 创建app实例,并传入参数app= QApplication(sys.argv)# 创建对象main = QLabelBuddy()# 创建窗口main.show()# 进入程序的主循环,并通过exit函数,确保主循环安全结束(该释放资源的释放资源)sys.exit(app.exec_())

效果如下:

28.QLineEdit控件与回显模式(EchoMode)

在controls文件夹里,新建QLineEditEchoMode.py文件,执行代码:

# QLineEdit控件与回显模式
# QLineEdit控件的基本功能:1.输入单行的文本 2.设置回显模式EcoMode"""
EcoMode(回显模式)
4种回显模式
1.Normal 正常的显示
2.Normal  不显示   类似于linux中输入密码没反应 但已经提交
3,Password  密码式的显示   类似于输入密码出现小黑点或*号
4,PasswordEchoOnEdit     密码显示编辑模式   常见于手机端,类似于  输入一个字母A,前两秒编辑框里显示的是A,过了一两秒编程框里变成的一个点或者*号"""
import sys
from PyQt5.QtWidgets import *# 从QWidget窗口类里面继承
class QLineEditEchoMode(QWidget):def __init__(self):super(QLineEditEchoMode,self).__init__()self.initUI()# 编写初始化方法def initUI(self):# 设置窗口标题self.setWindowTitle('文本输入框的回显模式')# 创建表单布局formLayout = QFormLayout()# 根据4种回显模式,分别创建4种表单布局# 第一种回显模式normalLineEdit = QLineEdit()# 第二种回显模式noEchoLineEdit = QLineEdit()# 第三种回显模式passwordLineEdit = QLineEdit()# 第四种回显模式passwordEchoONEditLineEdit = QLineEdit()# 把这四个控件添加到表单布局里面formLayout.addRow("Normal",normalLineEdit)formLayout.addRow("NoEcho",noEchoLineEdit)formLayout.addRow("Password",passwordLineEdit)formLayout.addRow("PasswordEchoOnEdit",passwordEchoONEditLineEdit)# 为每个文本框设置placeholdertext,就是当输入框没有输入时,以灰色字体显示这个文本框的提示normalLineEdit.setPlaceholderText("Normal")normalLineEdit.setPlaceholderText("NoEcho")passwordLineEdit.setPlaceholderText("Password")passwordEchoONEditLineEdit.setPlaceholderText("PasswprdEchoOnEdit")# 设置模式normalLineEdit.setEchoMode(QLineEdit.Normal)noEchoLineEdit.setEchoMode(QLineEdit.NoEcho)passwordLineEdit.setEchoMode(QLineEdit.Password)passwordEchoONEditLineEdit.setEchoMode(QLineEdit.PasswordEchoOnEdit)# 应用表单布局self.setLayout(formLayout)# 防止别的脚本调用,只有自己单独运行时,才会调用下面代码
if __name__ == '__main__':# 创建app实例,并传入参数app= QApplication(sys.argv)# 创建对象main = QLineEditEchoMode()# 创建窗口main.show()# 进入程序的主循环,并通过exit函数,确保主循环安全结束(该释放资源的释放资源)sys.exit(app.exec_())

效果如下:

28.限制QLineEdit控件的输入(校验器)

在controls文件夹里,新建QLineEditEValidator.py文件,执行代码:

# 限制QLineEdit控件的输入(校验器)   只能输入满足格式的数据
# 如限制只能输入整数、浮点数或满足一定条件的字符串# 本次演示做三种限制: 1.整数  2.浮点数   3.字母或者数字import sys
from PyQt5.QtWidgets import *
# 导入PyQt5的正则(三个校验器,第三个可自定义)
from PyQt5.QtGui import QIntValidator,QDoubleValidator,QRegExpValidator
# 导入PyQt5里正则表达式的一个类QRegExp
from PyQt5.QtCore import QRegExp# 编写一个类,从QWidget窗口类里面继承class QLineEditValidator(QWidget):def __init__(self):super(QLineEditValidator,self).__init__()self.initUI()# 编写初始化方法def initUI(self):# 设置一下窗口标题self.setWindowTitle('校验器')# 创建表单布局formLayout = QFormLayout()# 创建三个文本输入框intLineEdit = QLineEdit()doubleLineEdit = QLineEdit()validatorLineEdit = QLineEdit()# 将这三个控件添加到form表单布局里formLayout.addRow('整数类型',intLineEdit)formLayout.addRow('浮点类型',doubleLineEdit)formLayout.addRow('数字和字母',validatorLineEdit)# 为每个文本框设置placeholdertext,就是当输入框没有输入时,以灰色字体显示这个文本框的提示intLineEdit.setPlaceholderText('整数')doubleLineEdit.setPlaceholderText('浮点型')validatorLineEdit.setPlaceholderText('字母和数字')# 创建整数校验器inValidator = QIntValidator(self)# 设置整数的范围 [1,99]inValidator.setRange(1,99)# 创建浮点校验器doubleValidator = QDoubleValidator(self)# 设置浮点校验器[-360,360]doubleValidator.setRange(-360,-360)# 小数点的表示doubleValidator.setNotation(QDoubleValidator.StandardNotation)# 设置精度,小数点2位doubleValidator.setDecimals(2)# 创建数字和字母的正则表达式reg = QRegExp('[a-zA-Z0-9]+$')   # 此时+表示至少有一个# 创建数字和字母的校验器validator = QRegExpValidator(self)# 将正则表达式放置在校验器内validator.setRegExp(reg)# 设置校验器intLineEdit.setValidator(inValidator)doubleLineEdit.setValidator(doubleValidator)validatorLineEdit.setValidator(validator)# 应用表单布局self.setLayout(formLayout)# 防止别的脚本调用,只有自己单独运行时,才会调用下面代码
if __name__ == '__main__':# 创建app实例,并传入参数app= QApplication(sys.argv)# 创建对象main = QLineEditValidator()# 创建窗口main.show()# 进入程序的主循环,并通过exit函数,确保主循环安全结束(该释放资源的释放资源)sys.exit(app.exec_())

效果如下:

29.使用掩码限制QLineEdit控件的输入
掩码 说明
A ASCⅡ字母字符是必须输入的(A-Z、a-z)
a ASCⅡ字母字符是允许输入的,但不是必需的(A-Z、a-z)
N ASCⅡ字母字符是必须输入的(A-Z、a-z、0-9)
n ASCⅡ字母的允许输入的,但不是必需的(A-Z、a-z、0-9)
X 任何字符都是必须输入的
x 任何字符都是允许输入的,但不是必需的
9 ASCⅡ数字字符是必须输入的(0-9)
0 ASCⅡ数字字符是允许输入的,但不是必需的(0-9)
D ASCⅡ数字字符是必须输入的(1-9)
d ASCⅡ数字字符是允许输入的,但不是必需的(1-9)
# ASCⅡ数字字符或加减符号是允许输入的,但不是必需的
H 十六进制格式字符是必须输入的(A-F、a-f、0-9)
h 十六进制格式字符是允许输入的,但不是必需的(A-F、a-f、0-9)
B 二进制格式字符是必须输入 的(0,1)
b 二进制格式字符是允许输入的,但不是必需的(0,1)
> 所有的字母字符都大写
< 所有的字母字符都小写
! 关闭大小写转换
\ 使用""转义上面列出的字符

在controls文件夹里,新建QLineEditMask.py文件,执行代码:

# 使用掩码限制QLineEdit控件的输入import sys
from PyQt5.QtWidgets import *# 从QWidget窗口类里面继承
class QLineEditMask(QWidget):def __init__(self):super(QLineEditMask,self).__init__()self.initUI()# 规范代码,初始化直接写在一个方法里def initUI(self):# 设置窗口的标题self.setWindowTitle('用掩码限制QLineEdit控件的输入')# 创建表单布局formLayout = QFormLayout()# 创建四个控件# 第一个,IP控件   192.168.11.11ipLineEdit = QLineEdit()# 第二个 mac地址 (mac地址也叫物理地址和局域网地址,主要用于确认网上设备的地址,类似于身份证号,具有唯一标识)# 如:00-16-EA-AE-3C-40就是一个MAC地址macLineEdit = QLineEdit()# 第三个 显示日期控件dataLineEdit = QLineEdit()# 第四个 许可证licenseLineEdit = QLineEdit()# 设置掩码,通过setInputMask方法ipLineEdit.setInputMask('000.000.000.000;_')   # 后面分号指如果没有输入时,显示为"_"macLineEdit.setInputMask('HH:HH:HH:HH:HH:HH;_')dataLineEdit.setInputMask('0000-00-00')licenseLineEdit.setInputMask('>AAAAA-AAAAA-AAAAA-AAAAA-AAAAA;#')   # 后面# 号指如果没有输入时,显示为"#"# 把这四个控件都添加到表单布局里面formLayout.addRow('数字掩码',ipLineEdit)formLayout.addRow('Mac掩码',macLineEdit)formLayout.addRow('日期掩码',dataLineEdit)formLayout.addRow("许可证掩码",licenseLineEdit)# 应用于表单布局self.setLayout(formLayout)# 防止别的脚本调用,只有自己单独运行时,才会调用下面代码
if __name__ == '__main__':# 创建app实例,并传入参数app= QApplication(sys.argv)# 创建对象main = QLineEditMask()# 创建窗口main.show()# 进入程序的主循环,并通过exit函数,确保主循环安全结束(该释放资源的释放资源)sys.exit(app.exec_())

效果展示:

30.QLineEdit控件综合案例

在controls文件夹里,新建QLineEditDemo.py文件,执行代码:

# QLineEdit综合案例import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import Qt# 创建一个类,从QWidget窗口类里面继承
class QLineEditDemo(QWidget):def __init__(self):super(QLineEditDemo,self).__init__()self.initUI()# 编写初始化方法def initUI(self):# 创建多个edit对象# 创建第一个控件edit1 = QLineEdit()# 使用int校验器edit1.setValidator(QIntValidator())# 设置文本框最大长度(位数),即不超过9999edit1.setMaxLength(4)# 设置文本右对齐edit1.setAlignment(Qt.AlignRight)# 设置文本字体为Arial 字号 20edit1.setFont(QFont('Arial',20))# 创建第二个控件edit2 = QLineEdit()# 使用浮点校验器  范围0.99-99.99 精度为2edit2.setValidator(QDoubleValidator(0.99,99.99,2))# 未设置字体字号,对齐方式# 创建第三个控件edit3 = QLineEdit()# 使用掩码    掩码9表示 :ASCⅡ数字字符是必须输入的(0-9)edit3.setInputMask('99_9999_999999;#')  # 后面'#'号指没有输入时,显示为'#'# 创建第四个控件edit4 = QLineEdit()# 绑定事件,当文本变化时,响应到槽edit4.textChanged.connect(self.textChanged)# 创建第五个控件edit5 = QLineEdit()# 设置回显模式edit5.setEchoMode(QLineEdit.Password)# 绑定事件,当编辑完成时,响应到槽edit5.editingFinished.connect(self.enterPress)# 创建第六个控件edit6 =QLineEdit()# 设为只读edit6.setReadOnly(True)# 创建表单布局formLayout = QFormLayout()# 把控件添加到表单里formLayout.addRow('整数校验',edit1)formLayout.addRow('浮点数校验',edit2)formLayout.addRow('Input Mask',edit3)formLayout.addRow('文本变化',edit4)formLayout.addRow('密码',edit5)formLayout.addRow('只读',edit6)# 应用于表单布局self.setLayout(formLayout)# 设置窗口的标题self.setWindowTitle('QLineEdit综合案例')# 当文本变化时,触发事件# 定义槽一def textChanged(self,text):print('输入的文本:' + text)# 定义槽二def enterPress(self):print('已输入值')
# 防止别的脚本调用,只有自己单独运行时,才会调用下面代码
if __name__ == '__main__':# 创建app实例,并传入参数app= QApplication(sys.argv)# 创建对象main = QLineEditDemo()# 创建窗口main.show()# 进入程序的主循环,并通过exit函数,确保主循环安全结束(该释放资源的释放资源)sys.exit(app.exec_())

效果展示:

31.使用QTextEdit控件输入多行文本

在controls文件夹里,新建QTextEdit.py文件,执行代码:

# QTextEdit控件# QTextLine只能输入一行文本,输入多行文本用QTextEdit  常用功能:获得文本和设置文本,除了支持普通的文本,还支持富文本(改变颜色,设置尺寸)import sys
from PyQt5.QtWidgets import *# 编写一个类,从QWidget里面继承
class QTextEditDemo(QWidget):def __init__(self):super(QTextEditDemo,self).__init__()self.initUI()# 编写初始化方法 规范代码,初始化写在一个方法里def initUI(self):# 设置窗口的标题self.setWindowTitle('QTextEdit控件演示')# 设置窗口的尺寸self.resize(300,300)# 创建全局控件  为什么要创建去全局控件,在槽方法里需要调用self.textEdit = QTextEdit()# 创建全局按钮# 按钮一:显示文本# buttonText = QPushButton('显示文本')self.buttonText = QPushButton('显示文本')# 按钮二:显示HTML# buttonHTML = QPushButton('显示HTML')self.buttonHTML = QPushButton('显示HTML')# 按钮三:获取文本# buttonToText = QPushButton('获取文本')self.buttonToText = QPushButton('获取文本')# 按钮四:获取HTML# buttonToHTML = QPushButton('获取HTML')self.buttonToHTML = QPushButton('获取HTML')# 创建垂直布局layout = QVBoxLayout()# 把控件添加到垂直布局里面layout.addWidget(self.textEdit)# layout.addWidget(buttonText)# layout.addWidget(buttonHTML)layout.addWidget(self.buttonText)layout.addWidget(self.buttonHTML)layout.addWidget(self.buttonToText)layout.addWidget(self.buttonToHTML)# 应用于垂直布局self.setLayout(layout)# 把槽绑定到单击按钮信号上#     buttonText.clicked.connect(self.onClick_ButtonText)#     buttonHTML.clicked.connect(self.onClick_ButtonHTML)self.buttonText.clicked.connect(self.onClick_ButtonText)self.buttonHTML.clicked.connect(self.onClick_ButtonHTML)self.buttonToText.clicked.connect(self.onClick_ButtonToText)self.buttonToHTML.clicked.connect(self.onClick_ButtonToHTML)# 定义槽方法一def onClick_ButtonText(self):# 调用文本框设置普通文本self.textEdit.setPlainText('Hello World,世界你好吗?')# 定义槽方法二def onClick_ButtonHTML(self):# 调用文本框设置HTML(富文本)self.textEdit.setHtml('<font color="blue" size="5">Hello World</font>')# 定义获取模块的两个槽# 定义槽方法三def onClick_ButtonToText(self):# 调用文本框设置普通文本print(self.textEdit.toPlainText())# 定义槽方法四def onClick_ButtonToHTML(self):# 调用文本框设置HTML(富文本)print(self.textEdit.toHtml())# 防止别的脚本调用,只有自己单独运行,才会调用下面代码
if __name__ == '__main__':# 创建app实例,并传入参数app =  QApplication(sys.argv)# 设置图标# app.setWindowIcon(QIcon('images/001.jpg'))# 创建对象main = QTextEditDemo()# 创建窗口main.show()# 进入程序的主循环,并通过exit函数确保主循环安全结束(该释放资源的一定要释放)sys.exit(app.exec_())

效果展示:

32.按钮控件(QPushButton)

在controls文件夹里,新建QPushButtonDemo.py文件,执行代码:

# 按钮控件(QPushButton)
# 按钮有多个控件,它的父类QAbstractButton
# 子类有: QPushButton   AToolButton(工具条按钮) QRadioButton(单选按钮)  QCheckBox(复选按钮)import sys
# QtCore是Qt的精髓(包括五大模块:元对象系统,属性系统,对象模型,对象树,信号槽)
from PyQt5.QtCore import *
# QtGui 显示应用程序图标,工具提示和各种鼠标光标。
from PyQt5.QtGui import *
# Qt Widgets模块提供了一组UI元素来创建经典的桌面风格的用户界面。
from PyQt5.QtWidgets import *# 创建一个类,基于QDialog    QDialog是对话窗口的基类。没有菜单栏、工具栏、状态栏
class QPushButtonDemo(QDialog):def __init__(self):super(QPushButtonDemo,self).__init__()self.initUI()# 编写初始化方法,规范代码,初始化写在一个方法里def initUI(self):# 设置窗口标题self.setWindowTitle('QPushButton Demo')# 创建垂直布局layout = QVBoxLayout()# 创建四个buttonself.button1 = QPushButton('第1个按钮')# 通过setText获得文本self.button1.setText('First Button1')# 设置按钮按下自动弹起# # 按钮可复选的,可核对的self.button1.setCheckable(True)# 设置开关self.button1.toggle()# 上面两行代码,此时setCheckable为True时,调用toggle方法,按钮为选中状态,再调一次toggle方法时,处于未选中状态# 把槽绑定到单击按钮信号上# 通过两种方式将信息和槽相连# 信号和槽相连 方式一self.button1.clicked.connect(lambda :self.whichButton(self.button1))# 两个信号绑定到一个槽上   信号和槽是多对多的关系# 信号和槽相连 方式二self.button1.clicked.connect(self.buttonState)# 创建button2控件  在文本前显示图像self.button2 = QPushButton('图像按钮')# 给button2设置图形self.button2.setIcon(QIcon(QPixmap('./images/4.jpg')))# 把button2与槽连接self.button2.clicked.connect(lambda:self.whichButton(self.button2))# 创建button3控件,让按钮不可用self.button3 = QPushButton('不可用的按钮')# 设置按钮不可用self.button3.setEnabled(False)# 创建button4控件,为默认按钮(点回车可以执行的按钮),并给它加热键  按Alt + M 就可以直接调用这个button# 默认按钮一个窗口只能有一个self.button4 = QPushButton('&MyButton')# 设置button4按钮为默认按钮self.button4.setDefault(True)# 把button4与槽连接self.button4.clicked.connect(lambda :self.whichButton(self.button4))# 把控件添加到布局里layout.addWidget(self.button1)layout.addWidget(self.button2)layout.addWidget(self.button3)layout.addWidget(self.button4)# 应用于垂直布局self.setLayout(layout)# 设置窗口尺寸self.resize(400,300)# 编写槽函数# 多个按钮多个信号,同时使用一个槽,需要区分到底按了哪一个按钮# 目前有两种方法#第一种,用sender()方法# def whichButton(self):# self.sender()# 第二种,传参数,比如def whichButton(self,btn):print('被单击的按钮是<' + btn.text() + '>')# 编写第二个槽def buttonState(self):# 判断是否被选中if self.button1.isChecked():print('按钮1已经被选中')else:print('按钮1未被选中')# 防止别的脚本调用,只有自己单独运行,才会调用下面代码
if __name__ == '__main__':# 创建app实例,并传入参数app =  QApplication(sys.argv)# 设置图标# app.setWindowIcon(QIcon('images/001.jpg'))# 创建对象main = QPushButtonDemo()# 创建窗口main.show()# 进入程序的主循环,并通过exit函数确保主循环安全结束(该释放资源的一定要释放)sys.exit(app.exec_())

效果展示:

33.单选按钮控件(QRadioButton)

在controls文件夹里,新建QRadioButtonDemo.py文件,执行代码:

"""
单选按钮控件(QRadioButton)
"""
import sys
# QtCore是Qt的精髓(包括五大模块:元对象系统,属性系统,对象模型,对象树,信号槽)
from PyQt5.QtCore import *
# QtGui 显示应用程序图标,工具提示和各种鼠标光标。
from PyQt5.QtGui import *
# Qt Widgets模块提供了一组UI元素来创建经典的桌面风格的用户界面。
from PyQt5.QtWidgets import *class RadioButtonDemo(QWidget):def __init__(self):super(RadioButtonDemo,self).__init__()self.initUI()def initUI(self):# 设置窗口标题self.setWindowTitle('QRadioButton')# 把是所有的单选按钮都放在一个容器里,才能实现单选# 创建水平布局layout = QHBoxLayout()# 创建button1控件self.button1 = QRadioButton('单选按钮1')# 设button1默认为选中状态self.button1.setChecked(True)# 创建button2控件self.button2 = QRadioButton('单选按钮2')# 连接信息槽# toggle是状态切换的信号self.button1.toggled.connect(self.buttonState)self.button2.toggled.connect(self.buttonState)# 把控件添加到水平布局里layout.addWidget(self.button1)layout.addWidget(self.button2)# 应用于水平布局self.setLayout(layout)# 编写槽# def buttonState(self):#     # 控件获取数据#     radioButton = self.sender()#     # 判断获取的数据的文本是否是‘单选按钮1’#     if radioButton.text() == '单选按钮1':#         # 判断获取的数据的文本是‘单选按钮1’的是否被选中#         if radioButton.isChecked() == True:#             # 如果被选中#             print('<' + radioButton.text() + '>被选中' )#         else:#             print('<' + radioButton.text() + '>被取消选中状态')#     # 判断获取的数据的文本是否是‘单选按钮2’#     if radioButton.text() == '单选按钮2':#         # 判断获取的数据的文本是‘单选按钮2’的是否被选中#         if radioButton.isChecked() == True:#             # 如果被选中#             print('<' + radioButton.text() + '>被选中')#         else:#             print('<' + radioButton.text() + '>被取消选中状态')def buttonState(self):# 控件获取数据radioButton = self.sender()if radioButton.isChecked() == True:# 如果被选中print('<' + radioButton.text() + '>被选中')else:print('<' + radioButton.text() + '>被取消选中状态')# 防止别的脚本调用,只有自己单独运行时,才会调用下面代码
if __name__ == '__main__':# 创建app实例,并传入参数app= QApplication(sys.argv)# 创建对象main = RadioButtonDemo()# 创建窗口main.show()# 进入程序的主循环,并通过exit函数,确保主循环安全结束(该释放资源的释放资源)sys.exit(app.exec_())

效果展示:

34.复选框控件(QCheckBox)

复选框控件也称为多选控件

在controls文件夹里,新建QCheckBoxDemo.py文件,执行代码:

"""
复选框控件(QCheckBox)
作用:同时可选中多个控件
复选框控件有三种状态:
未选中: 0
半选中: 1
选中:   2"""
import sys
# QtCore是Qt的精髓(包括五大模块:元对象系统,属性系统,对象模型,对象树,信号槽)
from PyQt5.QtCore import *
# QtGui 显示应用程序图标,工具提示和各种鼠标光标。
from PyQt5.QtGui import *
# Qt Widgets模块提供了一组UI元素来创建经典的桌面风格的用户界面。
from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qtclass QCheckBoxDemo(QWidget):def __init__(self):super(QCheckBoxDemo,self).__init__()self.initUI()def initUI(self):# 设置窗口标题self.setWindowTitle('复选框控件演示')# 创建水平布局layout = QHBoxLayout()# 创建checkBox1复选框控件self.checkBox1 = QCheckBox('复选框控件1')#设置复选框默认为选中状态self.checkBox1.setChecked(True)# 创建checkBox2复选框控件# 普通控件,状态是未选中self.checkBox2 = QCheckBox('复选框控件2')# 创建checkBox3复选框控件 状态是半选中self.checkBox3 = QCheckBox('复选框控件3')# 处于半选中状态,需要下面两行代码self.checkBox3.setTristate(True)# 需要单独导Qt包   from PyQt5.QtCore import Qtself.checkBox3.setCheckState(Qt.PartiallyChecked)# 应用于水平布局self.setLayout(layout)# 将信号与槽绑定# 状态变化信号self.checkBox1.stateChanged.connect(lambda: self.checkboxState(self.checkBox1))self.checkBox2.stateChanged.connect(lambda: self.checkboxState(self.checkBox2))self.checkBox3.stateChanged.connect(lambda: self.checkboxState(self.checkBox3))# 把控件添加到水平布局里layout.addWidget(self.checkBox1)layout.addWidget(self.checkBox2)layout.addWidget(self.checkBox3)# 编写槽方法# 通过checkState可以设置三种状态def checkboxState(self,cb):check1Status = self.checkBox1.text() + ', isChecked=' + str(self.checkBox1.isChecked()) + ',checkState=' +str(self.checkBox1.checkState()) + '\n'check2Status = self.checkBox2.text() + ', isChecked=' + str(self.checkBox2.isChecked()) + ',checkState=' +str(self.checkBox2.checkState()) + '\n'check3Status = self.checkBox3.text() + ', isChecked=' + str(self.checkBox3.isChecked()) + ',checkState=' +str(self.checkBox3.checkState()) + '\n'print(check1Status + check2Status + check3Status)# 防止别的脚本调用,只有自己单独运行时,才会调用下面代码
if __name__ == '__main__':# 创建app实例,并传入参数app= QApplication(sys.argv)# 创建对象main = QCheckBoxDemo()# 创建窗口main.show()# 进入程序的主循环,并通过exit函数,确保主循环安全结束(该释放资源的释放资源)sys.exit(app.exec_())

效果展示

35.下拉列表控件(QComboBox)

在controls文件夹里,新建QComboBoxDemo.py文件,执行代码:

"""
下拉列表控件需要了解3点
1.如何将列表项添加到QComboBox控件中2.如何获取选中的列表项"""
import sys
# QtCore是Qt的精髓(包括五大模块:元对象系统,属性系统,对象模型,对象树,信号槽)
from PyQt5.QtCore import *
# QtGui 显示应用程序图标,工具提示和各种鼠标光标。
from PyQt5.QtGui import *
# Qt Widgets模块提供了一组UI元素来创建经典的桌面风格的用户界面。
from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qtclass QComboBoxDemo(QWidget):def __init__(self):super(QComboBoxDemo,self).__init__()self.initUI()# 编写初始化方法def initUI(self):# 设置窗口标题self.setWindowTitle('下拉列表控件演示')# 设置窗口尺寸self.resize(300,100)# 创建垂直布局layout = QVBoxLayout()# 创建label控件self.label = QLabel('请选择编程语言')# 创建QComboBox控件self.cb = QComboBox()# 用QComboBox里面的addItem添加self.cb.addItem('C++')self.cb.addItem('Python')# 也可以直接添加多个self.cb.addItems(['Java','Go','C','C#'])# 绑定信号和槽# currentIndexChanged 当前索引变化,从0开始self.cb.currentIndexChanged.connect(self.selectionChange)# 把控件添加到垂直布局里layout.addWidget(self.label)layout.addWidget(self.cb)# 应用于垂直布局self.setLayout(layout)# 槽方法# 默认传两个参数,一个是控件本身,一个是索引def selectionChange(self,i):# 得到当前选择的文本self.label.setText(self.cb.currentText())# 调整尺寸self.label.adjustSize()# 通过循环查看状态for count in range(self.cb.count()):# 根据索引,得到当前项的文本print('item' + str(count) + '=' + self.cb.itemText(count))print('current index',i,'selection changed',self.cb.currentText())# 防止别的脚本调用,只有自己单独运行时,才会调用下面代码
if __name__ == '__main__':# 创建app实例,并传入参数app= QApplication(sys.argv)# 创建对象main = QComboBoxDemo()# 创建窗口main.show()# 进入程序的主循环,并通过exit函数,确保主循环安全结束(该释放资源的释放资源)sys.exit(app.exec_())

效果展示

36.计数器控件(QSpinBox)

在controls文件夹里,新建QSpinBoxDemo.py文件,执行代码:

"""
计数器控件(QSpinBox)
用来控制一个数字的增加或减少
"""# 显示数字,获取数字,查看数字变化
import sys
# QtCore是Qt的精髓(包括五大模块:元对象系统,属性系统,对象模型,对象树,信号槽)
from PyQt5.QtCore import *
# QtGui 显示应用程序图标,工具提示和各种鼠标光标。
from PyQt5.QtGui import *
# Qt Widgets模块提供了一组UI元素来创建经典的桌面风格的用户界面。
from PyQt5.QtWidgets import *class QSpinBoxDemo(QWidget):def __init__(self):super(QSpinBoxDemo, self).__init__()self.initUI()# 编写初始化方法def initUI(self):# 设置窗口标题self.setWindowTitle('QSpinBox演示')# 设置窗口尺寸self.resize(300,100)# 创建垂直布局layout = QVBoxLayout()# 创建label控件self.label = QLabel('当前值')# 设置label控件的文字居中self.label.setAlignment(Qt.AlignCenter)# 创建QSpinBox控件self.sb = QSpinBox()#给控件设置默认值,从18开始变self.sb .setValue(18)#给控件设置范围,最小为19,最大为42self.sb.setRange(19,42)# 添加步长,让每次增2self.sb.setSingleStep(2)# 把控件添加到垂直布局里layout.addWidget(self.label)layout.addWidget(self.sb)# 信号槽绑定# 当value值发生变化时的方法self.sb.valueChanged.connect(self.valueChange)# 应用于垂直布局self.setLayout(layout)# 槽方法def valueChange(self):# 获得的字段self.label.setText('当前值:' + str(self.sb.value()))# 防止别的脚本调用,只有自己单独运行时,才会调用下面代码
if __name__ == '__main__':# 创建app实例,并传入参数app= QApplication(sys.argv)# 创建对象main = QSpinBoxDemo()# 创建窗口main.show()# 进入程序的主循环,并通过exit函数,确保主循环安全结束(该释放资源的释放资源)sys.exit(app.exec_())

效果展示:

37.滑块控件(QSlider)

在controls文件夹里,新建QSliderDemo.py文件,执行代码:

"""
滑块控件
通过滑块左右或者上下拉动来控制数字变化
"""
# 如何通过滑块标签来设置字体的大小import sys
# QtCore是Qt的精髓(包括五大模块:元对象系统,属性系统,对象模型,对象树,信号槽)
from PyQt5.QtCore import *
# QtGui 显示应用程序图标,工具提示和各种鼠标光标。
from PyQt5.QtGui import *
# Qt Widgets模块提供了一组UI元素来创建经典的桌面风格的用户界面。
from PyQt5.QtWidgets import *class QSliderDemo(QWidget):def __init__(self):super(QSliderDemo, self).__init__()self.initUI()def initUI(self):# 设置窗口标题self.setWindowTitle('滑块控件演示')# 设置窗口尺寸self.resize(300,300)# 创建垂直布局layout = QVBoxLayout()# 创建label控件self.label = QLabel('你好,PyQt5')# 让label控件居中显示self.label.setAlignment(Qt.AlignCenter)# 创建滑块控件,有两种:水平和垂直# 创建水平的滑块控件sliderself.slider = QSlider(Qt.Horizontal)# 创建垂直的滑块控件slider1self.slider1 =   QSlider(Qt.Vertical)# 设置最小值12self.slider.setMinimum(12)self.slider1.setMinimum(12)# 设置最大值self.slider.setMaximum(58)self.slider1.setMaximum(58)# 步长self.slider.setSingleStep(3)self.slider1.setSingleStep(3)# 设置当前值self.slider.setValue(18)self.slider1.setValue(12)# 设置刻度的位置,刻度在下方self.slider.setTickPosition(QSlider.TicksBelow)# 设置刻度的位置,刻度在左方self.slider1.setTickPosition(QSlider.TicksLeft)# 设置刻度的间隔self.slider.setTickInterval(6)self.slider1.setTickInterval(3)# 把控件添加到垂直布局里layout.addWidget(self.label)layout.addWidget(self.slider)layout.addWidget(self.slider1)#信号槽的绑定self.slider.valueChanged.connect(self.valueChange)self.slider1.valueChanged.connect(self.valueChange)# 应用于垂直布局self.setLayout(layout)# 槽方法def valueChange(self):print('当前值:%s' % self.slider.value())print('当前值:%s' % self.slider1.value())# 获得值size = self.slider.value()size = self.slider1.value()# 设置字体字号,让字号通过值发生变化self.label.setFont(QFont('Arial',size))# 防止别的脚本调用,只有自己单独运行时,才会调用下面代码
if __name__ == '__main__':# 创建app实例,并传入参数app= QApplication(sys.argv)# 创建对象main = QSliderDemo()# 创建窗口main.show()# 进入程序的主循环,并通过exit函数,确保主循环安全结束(该释放资源的释放资源)sys.exit(app.exec_())

效果展示:

38.对话框(QDialog)

在controls文件夹里,新建QDialogDemo.py文件,执行代码:

"""
对话框的基类QDialog
在基类基础上有五种对话框
QMessageBox 消息对话框
QColorDialog 颜色对话框
QFileDialog  显示文件打开或保存对话框
QFontDialog  设置字体对话框
QInputDialog  输入信息对话框回顾:
PyQt5的三种窗口
QMainWindow  主窗口
QWidget  不确定窗口的用途时
QDialog  没有菜单的窗口,一个对话框"""
# 如何在主窗口里面显示对话框
import sys
# QtCore是Qt的精髓(包括五大模块:元对象系统,属性系统,对象模型,对象树,信号槽)
from PyQt5.QtCore import *
# QtGui 显示应用程序图标,工具提示和各种鼠标光标。
from PyQt5.QtGui import *
# Qt Widgets模块提供了一组UI元素来创建经典的桌面风格的用户界面。
from PyQt5.QtWidgets import *class QDialogDemo(QMainWindow):def __init__(self):super(QDialogDemo, self).__init__()self.initUI()def initUI(self):# 设置窗口标题self.setWindowTitle('QDialog案例')# 设置窗口尺寸self.resize(300,200)# 创建button控件,直接把button放在窗口上self.button = QPushButton(self)# 设置button控件文本self.button.setText('弹出对话框')# 移动button的位置self.button.move(50,50)# 将单击信号和槽绑定self.button.clicked.connect(self.showDialog)# 槽方法def showDialog(self):# 创建对话框dialog = QDialog()# 在对话框dialog里面放一个buttonbutton = QPushButton('确定',dialog)# 点击button按钮关闭  现成的槽button.clicked.connect(dialog.close)# 移动buttonbutton.move(50,50)# 给dialog设置标题dialog.setWindowTitle('对话框')# 设置对话框为模式状态,模式状态:即模式状态开启时,对话框窗口里的所有控件不可用dialog.setWindowModality(Qt.ApplicationModal)# 显示对话框dialog.exec()# 防止别的脚本调用,只有自己单独运行时,才会调用下面的代码
if __name__ == '__main__':# 创建app实例,并传入参数app = QApplication(sys.argv)# 创建对象main = QDialogDemo()# 创建窗口main.show()# 进入程序的主循环,并通过exit函数,确保主循环安全结束(该释放资源的释放)sys.exit(app.exec_())

效果展示:

39.消息对话框(QMessageBox)

在controls文件夹里,新建QMessageBoxDemo.py文件,执行代码:

"""
消息对话框 QMessageBox主要用于显示版本和其他软件的信息常用的有以下集中对话框
1.关于对话框
2.错误对话框
3.警告对话框
4.提问对话框
5.消息对话框以上对话框主要有以下两种差异
1.显示的对话框图标可能不同
2.显示的按钮个数,文字是不一样的"""import sys
# QtCore是Qt的精髓(包括五大模块:元对象系统,属性系统,对象模型,对象树,信号槽)
from PyQt5.QtCore import *
# QtGui 显示应用程序图标,工具提示和各种鼠标光标。
from PyQt5.QtGui import *
# Qt Widgets模块提供了一组UI元素来创建经典的桌面风格的用户界面。
from PyQt5.QtWidgets import *class QMessageBoxDemo(QWidget):def __init__(self):super(QMessageBoxDemo, self).__init__()self.initUI()def initUI(self):# 设置窗口标题self.setWindowTitle('QMessageBox演示')# 设置窗口尺寸self.resize(300,400)# 创建垂直布局layout = QVBoxLayout()# 创建button1控件self.button1 = QPushButton()# 设置button1的文本内容self.button1.setText('显示关于对话框')# 创建button2控件self.button2 = QPushButton()# 设置button2的文本内容self.button2.setText('显示消息对话框')# 创建button3控件self.button3 = QPushButton()# 设置button3的文本内容self.button3.setText('显示警告对话框')# 创建button4控件self.button4 = QPushButton()# 设置button4的文本内容self.button4.setText('显示错误对话框')# 创建button5控件self.button5 = QPushButton()# 设置button5的文本内容self.button5.setText('显示提问对话框')# 信号与槽绑定  (本次演示,多个信号都绑定在一个槽上)self.button1.clicked.connect(self.showDialog)self.button2.clicked.connect(self.showDialog)self.button3.clicked.connect(self.showDialog)self.button4.clicked.connect(self.showDialog)self.button5.clicked.connect(self.showDialog)# 把控件添加到布局里layout.addWidget(self.button1)layout.addWidget(self.button2)layout.addWidget(self.button3)layout.addWidget(self.button4)layout.addWidget(self.button5)# 应用于垂直布局self.setLayout(layout)# 槽方法def showDialog(self):text = self.sender().text()if text == '显示关于对话框':QMessageBox.about(self,'关于','这是一个关于对话框')elif text == '显示消息对话框':# 两个选项,一个YES,一个No,还有一个默认的值,按回车之后会Yesreply = QMessageBox.information(self,'消息','这是一个消息对话框',QMessageBox.Yes | QMessageBox.No,QMessageBox.Yes)print(reply == QMessageBox.Yes)elif text == '显示警告对话框':QMessageBox.warning(self,'警告','这是一个警告对话框',QMessageBox.Yes | QMessageBox.No,QMessageBox.Yes)elif text == '显示错误对话框':QMessageBox.critical(self, '错误', '这是一个错误对话框', QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)elif text == '显示提问对话框':QMessageBox.question(self, '提问', '这是一个提问对话框', QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)if __name__ == '__main__':app = QApplication(sys.argv)main = QMessageBoxDemo()main.show()sys.exit(app.exec_())

效果展示

40.输入对话框(QInputDialog)

在controls文件夹里,新建QInputDialogDemo.py文件,执行代码:

"""
输入对话框:QInputDialog
提供了若干个静态方法
QInputDialog.getItem  用来显示输入列表
QInputDialog.getText   用来显示录入文本
QInputDialog.getInt    用来显示输入整数的  计数器控件"""
import sys
# QtCore是Qt的精髓(包括五大模块:元对象系统,属性系统,对象模型,对象树,信号槽)
from PyQt5.QtCore import *
# QtGui 显示应用程序图标,工具提示和各种鼠标光标。
from PyQt5.QtGui import *
# Qt Widgets模块提供了一组UI元素来创建经典的桌面风格的用户界面。
from PyQt5.QtWidgets import *class QInputDialogDemo(QWidget):def __init__(self):super(QInputDialogDemo, self).__init__()self.initUI()# 编写初始化方法def initUI(self):# 设置窗口标题self.setWindowTitle('输入对话框')# 设置窗口尺寸self.resize(400,400)# 创建form表单布局layout = QFormLayout()# 创建button1控件self.button1 = QPushButton('获取列表中的选项')# 创建lineEdit1控件,放置在button1的右侧  在布局添加的时候设置self.lineEdit1 =QLineEdit()# 创建button2控件self.button2 = QPushButton('获取字符串')# 创建lineEdit2控件,放置在button2的右侧 在布局添加的时候设置self.lineEdit2 = QLineEdit()# 创建button3、lineEdit3控件self.button3 = QPushButton('获取整数')self.lineEdit3 = QLineEdit()# 绑定信号 槽self.button1.clicked.connect(self.getItem)self.button2.clicked.connect(self.getText)self.button3.clicked.connect(self.getInt)# 把控件添加到form表单布局里layout.addRow(self.button1,self.lineEdit1)layout.addRow(self.button2, self.lineEdit2)layout.addRow(self.button3, self.lineEdit3)# 应用于form表单布局self.setLayout(layout)# 槽方法def getItem(self):# 定义一个元组items =('C','C++','Ruby','Python','Java')item,ok = QInputDialog.getItem(self,'请选择编程语言','语言列表',items)if ok and item:self.lineEdit1.setText(item)def getText(self):text, ok = QInputDialog.getText(self,'文本输入框','输入姓名')if ok and text:self.lineEdit2.setText(text)def getInt(self):num, ok = QInputDialog.getInt(self,'整数输入框','输入数字')if ok and num:self.lineEdit3.setText(str(num))
if __name__ == '__main__':app = QApplication(sys.argv)main = QInputDialogDemo()main.show()sys.exit(app.exec_())

效果展示:

41.字体对话框(QFontDialog)

在controls文件夹里,新建QFontDialogDemo.py文件,执行代码:

"""
字体对话框 QFontDialog用来显示字体列表,并且选择某一个字体字号,然后返回
"""
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *class QFontDialogDemo(QWidget):def  __init__(self):super(QFontDialogDemo, self).__init__()self.initUI()def initUI(self):# 设置窗口标题self.setWindowTitle('FontDialog演示')# 设置窗口尺寸self.resize(300,100)# 创建一个垂直布局layout = QVBoxLayout()# 创建button控件self.fontButton = QPushButton('选择字体')# 创建label控件,用于接收设置的文本输入框self.fontLabel = QLabel('Hello,测试字体例子')# 绑定信号和槽self.fontButton.clicked.connect(self.getFont)# 把控件添加到布局里layout.addWidget(self.fontButton)layout.addWidget(self.fontLabel)# 应用于垂直布局self.setLayout(layout)# 槽方法def getFont(self):# 返回font对象,探测是否点ok或者cancel# getFont返回两个值font, ok = QFontDialog.getFont()if ok:self.fontLabel.setFont(font)if __name__ == '__main__':app = QApplication(sys.argv)main = QFontDialogDemo()main.show()sys.exit(app.exec_())

效果展示:

42.颜色对话框(QColorDialog)

在controls文件夹里,新建QColorDialogDemo.py文件,执行代码:

"""
颜色对话框 QColorDialog
"""import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *class QColorDialogDemo(QWidget):def __init__(self):super(QColorDialogDemo, self).__init__()self.initUI()# 编写初始化方法def initUI(self):# 设置窗口标签self.setWindowTitle('选择颜色')# 创建布局layout = QVBoxLayout()# 创建button控件self.colorButton = QPushButton('选择颜色')# 创建label控件,用于设置接收颜色的输入框self.colorLaber = QLabel('Hello,测试颜色')# 创建Bgbutton控件,用来设置背景色self.colorBgButton = QPushButton('设置背景色')# 绑定信号 槽self.colorButton.clicked.connect(self.getColor)self.colorBgButton.clicked.connect(self.getBgColor)# 把控件放在布局里layout.addWidget(self.colorButton)layout.addWidget(self.colorLaber)layout.addWidget(self.colorBgButton)# 应用布局self.setLayout(layout)# 槽方法def getColor(self):# 返回color对象,探测是否点ok或者cancel# getColor返回一个值color = QColorDialog.getColor()# 设置文字颜色# 调色板实例化p =QPalette()p.setColor(QPalette.WindowText,color)# 设置调色板self.colorLaber.setPalette(p)# 背景色槽方法def getBgColor(self):color =  QColorDialog.getColor()# 调色板设置p = QPalette()p.setColor(QPalette.Window,color)# 设置自动填充self.colorLaber.setAutoFillBackground(True)# 设置调色板self.colorLaber.setPalette(p)# 防止别的脚本调用,只有自己单独运行时,才会调用下面代码
if __name__ == '__main__':# 创建app实例,并传入参数app = QApplication(sys.argv)# 把类实例化main = QColorDialogDemo()# 设置窗口main.show()# 进入程序的主循环,通过exit函数,确保主循环安全结束sys.exit(app.exec_())

效果展示:

43.文件对话框(QFileDialog)

在controls文件夹里,新建QFileDialogDemo.py文件,执行代码:

"""
文件对话框 QFileDialog
最常用的是打开文件和保存文件对话框
"""
# 需求:
# 1.打开文件,显示到窗口上
# 2.打开文本文件,将文本文件的内容显示到窗口上import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *class QFileDialogDemo(QWidget):def __init__(self):super(QFileDialogDemo, self).__init__()self.initUI()# 编写初始化方法def initUI(self):# 设置窗口标题self.setWindowTitle('文件对话框演示')# 创建垂直布局layout = QVBoxLayout()# 创建button1控件,用于加载图片self.button1 = QPushButton('加载图片')# 创建label控件,把图像显示到label控件上self.imageLabel = QLabel()# 创建button2控件,用于加载文件self.button2 = QPushButton('加载文本文件')# 创建QTextEdit控件,来显示文本加载的内容self.contents = QTextEdit('显示文本加载内容')# 连接信号槽self.button1.clicked.connect(self.loadImage)self.button2.clicked.connect(self.loadText)# 把控件添加到垂直布局里layout.addWidget(self.button1)layout.addWidget(self.imageLabel)layout.addWidget(self.button2)layout.addWidget(self.contents)# 应用于垂直布局self.setLayout(layout)# 槽方法def loadImage(self):# 打开单个文件对话框# 下行代码第三个参数是默认路径,用 "."代替当前# 第四个参数:'图形文件 (*.jpg)'改成选中两种类型时有问题 '图形文件 (*.png,*.jpg)'# 弹出来的显示图片的窗口会随着图片尺寸大小的变化而变化fname,_ = QFileDialog.getOpenFileName(self,'打开文件','.','图形文件 (*.jpg)')# 得到图片文件名self.imageLabel.setPixmap(QPixmap(fname))def loadText(self):# 直接创建QFileDialog,第二种方法# 创建对象dialog = QFileDialog()# 设置文件创建模式dialog.setFileMode(QFileDialog.AnyFile)# 选择文件dialog.setFilter(QDir.Files)#打开文件if dialog.exec():# 如果打开成功filename = dialog.selectedFiles()# 打开文件,可以打开多个,取第一个f = open(filename[0],encoding='utf-8',mode='r')# 读取# 使用with的原因,自动关闭,当with读取结束后,会自动调用f里面的close方法关闭文档with f:data = f.read()self.contents.setText(data)# 防止别的脚本调用,只有自己单独运行时,才会调用下面代码
if __name__ == '__main__':# app实例化,并传递参数app = QApplication(sys.argv)# 创建对象main = QFileDialogDemo()# 创建窗口main.show()# 进入程序的主循环,通过exit函数sys.exit(app.exec_())

效果展示:

44.绘制API:绘制文本

新建drawing文件夹,在drawing文件夹里新建DrawText.py文件,执行代码:

"""
绘制API:绘制文本绘制API主要有三种类型
1.文本
2.各种图形(直线、点、椭圆、弧、扇形、多边形等)
3.图像绘制元素的类QPainter大致过程
painter = QPainter()
painter.begin()
painter.drawText(...)
painter.end()必须在paintEvent事件方法中绘制各种元素
这个事件自动调用,在创建窗口时,以及窗口尺寸发生变化时,会重新绘制,很快本质上, 窗口尺寸改变时,窗口上的所有元素都会重新绘制"""
import sys
from PyQt5.QtWidgets import  QApplication,QWidget
from PyQt5.QtGui import QPainter,QColor,QFont
from PyQt5.QtCore import Qtclass DrawText(QWidget):def __init__(self):super(DrawText, self).__init__()# 创建窗口标题self.setWindowTitle('在窗口上绘制文本')# 设置窗口尺寸self.resize(600,200)# 设置文本self.text = "PyQt5从入门到精通"# 定义事件方法# 参数两个,一个它自己,一个是eventdef paintEvent(self, event):# 创建QPainter对象painter = QPainter()painter.begin(self)print('aaaa')# 设置笔的颜色painter.setPen(QColor(123,21,3))# 设置字体和字号painter.setFont(QFont('SimSun',25))# 指定区域,设置对齐方式 居中painter.drawText(event.rect(),Qt.AlignCenter,self.text)painter.end()# 防止别的脚本调用,只有自己单独运行时,才会执行下面的代码
if __name__ == '__main__':# app实例化,并传参app = QApplication(sys.argv)# 创建对象main = DrawText()# 创建窗口main.show()# 进入主循环,调用exit方法sys.exit(app.exec_())

效果展示:

45.用像素点绘制正弦曲线

在drawing文件夹里新建DrawPoints.py文件,执行代码:

"""
用像素点绘制正弦曲线drawPoint(x,y)
"""
# 绘制两个周期的正弦曲线  -2Π到2Πimport sys,math
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import Qtclass DrawPoints(QWidget):def __init__(self):super(DrawPoints, self).__init__()# 设置窗口的大小self.resize(300,300)# 设置窗口标题self.setWindowTitle('在窗口上用像素点绘制2个周期的正弦曲线')def paintEvent(self,event):painter =QPainter()painter.begin(self)# 设置笔的颜色 固定 方法二painter.setPen(Qt.blue)# 获得窗口尺寸size = self.size()# 对水平轴进行循环,循环一千次for i in range(1000):x = 100 * (-1 + 2.0 * i/1000) + size.width()/2.0# pi 指的是Πy = -50 * math.sin((x - size.width()/2.0)* math.pi/50) + size.height()/2.0painter.drawPoint(x,y)painter.end()# 防止别的脚本调用,只有自己单独运行时,才会执行下面代码
if __name__ == '__main__':# app实例化,并传参app = QApplication(sys.argv)# 创建对象main = DrawPoints()# 创建窗口main.show()# 进入主循环,调用exit方法,确保主循环安全结束sys.exit(app.exec_())

效果展示:

46.绘制不同类型的直线

在drawing文件夹里新建DrawMultiLine.py文件,执行代码:

"""
绘制不同类型的直线"""
import sys,math
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import Qtclass DrawMultiLine(QWidget):def __init__(self):super(DrawMultiLine, self).__init__()self.resize(300,300)self.setWindowTitle('设置Pen的样式')def paintEvent(self, event):painter = QPainter()painter.begin(self)# 创建画笔   设置颜色,粗细  类型(实线,虚线)pen = QPen(Qt.red,3,Qt.SolidLine)# 设置对象painter.setPen(pen)# 绘图painter.drawLine(20,40,250,40)# 设置虚线pen.setStyle(Qt.DashLine)painter.setPen(pen)painter.drawLine(20,80,250,80)# 设置点划线pen.setStyle(Qt.DashDotDotLine)painter.setPen(pen)painter.drawLine(20,120,250,120)# 设置虚线pen.setStyle(Qt.DashLine)painter.setPen(pen)painter.drawLine(20,160,250,160)# 设置自定义pen.setStyle(Qt.CustomDashLine)pen.setDashPattern([1,2])painter.setPen(pen)painter.drawLine(20,200,20,200)size = self.size()# 绘制结束painter.end()# 防止其他脚本调用,只有运行该脚本时,才会执行下面代码
if __name__ == '__main__':# app实例化,并传参app = QApplication(sys.argv)# 创建对象main = DrawMultiLine()# 创建窗口main.show()# 进入主循环,调用exit方法,保证主循环安全结束sys.exit(app.exec_())

效果展示:

47.绘制各种图形

在drawing文件夹里新建DrawAll.py文件,执行代码:

"""
绘制各种图形
弧 圆形 矩形(正方形) 多边形 绘制图像
"""import sys,mathfrom PyQt5.QtWidgets import *
from  PyQt5.QtGui import *
from  PyQt5.QtCore import *class DrawAll(QWidget):def __init__(self):super(DrawAll, self).__init__()self.resize(400,600)self.setWindowTitle('绘制各种图形')# 定义事件def paintEvent(self, event):# 创建一个Qpainter对象qp = QPainter()# 绘制开始qp.begin(self)# 设置笔的颜色qp.setPen(Qt.blue)# 绘制弧#  确定一个区域rect = QRect(0,10,100,100)# alen:一个alen等于1/16度   所以表示45度,用45*16表示#  画50度,用50*16表示  参数  起  终qp.drawArc(rect,0,50*16)# 通过弧绘制圆#  更改笔的颜色qp.setPen(Qt.red)# 位置 从0 到360°qp.drawArc(120,10,100,100,0, 360* 16)# 绘制带弦的弧# 位置 从12°到130°qp.drawChord(10,120,100,100,12,130*16)# 绘制扇形#  位置  从12°到130°qp.drawPie(10,240,100,100,12,130*16)# 椭圆#  不需要指定开始角度和结束角度     宽和高不一样。 如果一样就成圆了qp.drawEllipse(120,120,150,100)# 通过椭圆绘制圆   距窗口的宽  距窗口的高   宽  高qp.drawEllipse(180, 300, 150, 150)# 绘制五边形#   需要指定五个点point1 = QPoint(140,380)point2 = QPoint(270,420)point3 = QPoint(290,512)point4 = QPoint(290,588)point5 = QPoint(200,533)#   创建一个多边形的对象polygon = QPolygon([point1,point2,point3,point4,point5])#  开始绘制五边形qp.drawPolygon(polygon)# 绘制图像#   装载图像image = QImage('../controls/images/5.png')#   指定绘制图像的区域   把图片缩小到原来的三分之一#    距离窗口的宽度  距离窗口的高度   宽缩小三分之一  高缩小三分之一rect = QRect(10,400,image.width()/3,image.height()/3)image.save('../controls/images/5.png')# 开始绘制图像qp.drawImage(rect,image)# 绘制结束qp.end()# 防止其他脚本调用,只有当这个脚本自己运行时,才会调用下面代码
if __name__ == '__main__':# app实例化,并传参app = QApplication(sys.argv)# 创建对象main = DrawAll()# 创建窗口main.show()# 进入主循环,调用exit函数,确保主循环安全结束sys.exit(app.exec_())

效果展示:

48.用画刷填充图形区域

在drawing文件夹里新建FillRect.py文件,执行代码:

"""
用画刷填充图形区域
"""import sys,math
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *class FillRect(QWidget):def __init__(self):super(FillRect, self).__init__()# 设置窗口标题self.setWindowTitle('用画刷填充区域')# 设置窗口尺寸self.resize(600,600)# 定义事件def paintEvent(self, e):# 创建QPainter对象qp = QPainter()# 绘制开始qp.begin(self)# 创建画刷对象  默认实心brush = QBrush(Qt.SolidPattern)# 设置画刷qp.setBrush(brush)# 绘制矩形,填充区域#   距窗口的宽   距窗口的高    绘制矩形的宽   绘制矩形的高qp.drawRect(30,15,150,60)# 创建画刷brush1 = QBrush(Qt.Dense1Pattern)# 设置画刷qp.setBrush(brush1)# 绘制矩形,填充区域#   距窗口的宽   距窗口的高    绘制矩形的宽   绘制矩形的高qp.drawRect(30,100,150,60)# 创建画刷brush2 = QBrush(Qt.Dense2Pattern)# 设置画刷qp.setBrush(brush2)# 绘制矩形,填充区域#   距窗口的宽   距窗口的高    绘制矩形的宽   绘制矩形的高qp.drawRect(30, 180, 150, 60)# 创建画刷brush3 = QBrush(Qt.Dense3Pattern)# 设置画刷qp.setBrush(brush3)# 绘制矩形,填充区域#   距窗口的宽   距窗口的高    绘制矩形的宽   绘制矩形的高qp.drawRect(30, 260, 150, 60)# 创建画刷brush4 = QBrush(Qt.HorPattern)# 设置画刷qp.setBrush(brush4)# 绘制矩形,填充区域#   距窗口的宽   距窗口的高    绘制矩形的宽   绘制矩形的高qp.drawRect(30, 340, 150, 60)# 绘制结束qp.end()# 防止其他脚本调用,单独调用此脚本,才会执行下面代码
if __name__ == '__main__':# app实例化,并传参app = QApplication(sys.argv)# 创建对象main = FillRect()# 创建窗口main.show()# 进入主循环,调用exit方法,确保主循环安全结束sys.exit(app.exec_())

效果展示:

49.让控件支持拖拽动作

新建drapclip文件夹,在drapclip文件夹里新建DrapDrop.py文件,执行代码:

"""
让控件支持拖拽动作
如果把A拖到B
A.setDragEnabled(True)   让A可以拖动
B.setAcceptDrops(True)   让B可以接收其他控件
B需要两个事件
1.dragEnterEvent    将A拖到B触发
2.dropEvent         在B的区域放下A时触发
"""
# demo:将一个文本输入框里面的文字拖到一个QChickBox控件里面,(把文字追加到QChickBox里面)import sys,math
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *# B
# QComboBox 下拉框
class MyComboBox(QComboBox):def __init__(self):super(MyComboBox, self).__init__()# 把这个控件SetAcceptDrops为True,就可以接收别的控件了self.setAcceptDrops(True)# 别的控件拖进来,还没松鼠标,还没触发def dragEnterEvent(self, e):print(e)# 查看接收的文本,如果有文本,进行处理if e.mimeDate().hasText():e.accept()else:e.ignore()# 把别的控件拖进来放下def dropEvent(self, e):# self指当前下拉列表控件# 得到一个文本输入框的文本self.addItem(e.mimeDate().text())# A
class DrapDropDemo(QWidget):def __init__(self):super(DrapDropDemo, self).__init__()# 创建一个form表单布局formLayout = QFormLayout()# 把控件添加到布局里formLayout.addRow(QLabel("请将左边的文本拖拽到右边的下拉列表中"))# 创建文本输入框  在左侧显示lineEdit = QLineEdit()# 被拖动的控件设置可以拖动  让QLineEdit控件可拖动lineEdit.setDragEnabled(True)# 创建下拉列表控件combo = MyComboBox()# 把控件添加到form布局里  左侧为lineEdit ,右侧为下拉列表控件formLayout.addRow(lineEdit,combo)# 应用于布局self.setLayout(formLayout)# 设置标题self.setWindowTitle('拖拽案例')# 防止别脚本调用,只有直接运行此脚本,才会执行下面代码
if __name__ == '__main__':# app实例化,并传参app = QApplication(sys.argv)# 创建对象main = DrapDropDemo()# 创建窗口main.show()# 进入主循环,调用exit方法,让主循环安全退出sys.exit(app.exec_())

效果展示:

bug:windows发生dragEnterEvent方法执行不了的问题,排查无果,待后期深入研究PyQt5之后再来填坑。

50.使用剪切板

在drapclip文件夹里新建ClipBoard.py文件,执行代码:

"""
使用剪贴板
"""
import sys,math
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *class ClipBoard(QDialog):def __init__(self):super(ClipBoard, self).__init__()# 创建6个按钮组件textCopyButton = QPushButton('复制文本')textPasteButton = QPushButton('粘贴文本')htmlCopyButton = QPushButton('复制HTML')htmlPasteButton = QPushButton('粘贴HTML')imageCopyButton = QPushButton('复制图像')imagePasteButton = QPushButton('粘贴图像')#  创建两个label控件,一个用来显示粘贴的文本   一个用来显示图像self.textLabel = QLabel('默认文本')self.imageLabel = QLabel('显示头像')self.imageLabel.setPixmap(QPixmap('../controls/images/5.png'))# 设置栅格布局layout = QGridLayout()# 把控件添加到布局里# 第一行第一列layout.addWidget(textCopyButton,0,0)# 第一行第二列layout.addWidget(imageCopyButton,0,1)#第一行第三列layout.addWidget(htmlCopyButton,0,2)# 第二行第一列layout.addWidget(textPasteButton,1,0)# 第二行第二列layout.addWidget(htmlPasteButton,1,1)# 第二行第三列layout.addWidget(imagePasteButton,1,2)# 第三行第一列   占一行占两列layout.addWidget(self.textLabel,2,0,1,2)# 第三行第三列layout.addWidget(self.imageLabel,2,2)# 应用于栅格布局self.setLayout(layout)# 绑定信号  槽# 分别为这六个按钮指定单击事件# 复制文本textCopyButton.clicked.connect(self.copyText)# 粘贴文本textPasteButton.clicked.connect(self.pasteText)# 复制HTMLhtmlCopyButton.clicked.connect(self.copyHtml)# 粘贴HTMLhtmlPasteButton.clicked.connect(self.pasteHtml)# 复制图像imageCopyButton.clicked.connect(self.copyImage)# 粘贴图像imagePasteButton.clicked.connect(self.pasteImage)# 设置窗口标题self.setWindowTitle('剪贴板演示')# 槽方法def copyText(self):# 设置剪切板clipboard = QApplication.clipboard()# 设置剪切板内容clipboard.setText('hello world')def pasteText(self):# 设置剪切板clipboard = QApplication.clipboard()# 设置剪切板内容# 把剪切板的内容直接放到label里self.textLabel.setText(clipboard.text())def copyHtml(self):# 获取数据类型mimeData = QMimeData()# 设置HTMLmimeData.setHtml('<b>Bold and <font color=red>Red</font></b>')# 获得剪切板clipborad = QApplication.clipboard()# 在剪切板设置数据clipborad.setMimeData(mimeData)def pasteHtml(self):# 获得剪切板clipboard = QApplication.clipboard()# 获得数据mimeData  = clipboard.mimeData()# 如果数据是html类型if mimeData.hasHtml():# 把html数据放在剪切板上self.textLabel.setText(mimeData.html())def copyImage(self):# 设置剪切板clipboard = QApplication.clipboard()# 设置剪切板内容clipboard.setPixmap(QPixmap('../controls/images/5.png'))def pasteImage(self):# 设置剪切板clipboard = QApplication.clipboard()# 设置剪切板的内容# 把剪切板的内容直接放到label里self.imageLabel.setPixmap(clipboard.pixmap())# 防止其他脚本调用,只有单独运行此脚本,才会调用下面代码
if __name__ == '__main__':# app实例,并传参app = QApplication(sys.argv)# 创建对象main = ClipBoard()# 创建窗口main.show()# 执行主循环,调用exit方法,确保主循环安全退出sys.exit(app.exec_())

效果展示:

51.日历控件

新建calendar_time文件夹,在calendar_time文件夹里新建MyCalendar.py文件,执行代码:

"""
日历控件
QCalendarWidget
"""
# 允许用户选择日期
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *class MyCalendar(QWidget):def __init__(self):super(MyCalendar, self).__init__()self.initUI()# 编写初始化方法,规范代码,初始化写在一个方法里def initUI(self):# 创建日历控件,全局的,在单击事件里面调用self.cal = QCalendarWidget(self)# 创建label控件,用于显示当前选择的日期# 这个label用绝对布局self.label = QLabel(self)# 显示当前日期date = self.cal.selectedDate()self.label.setText(date.toString('yyyy-MM-dd dddd'))# 移动label到相应的位置self.label.move(20,300)# 设置允许显示最小日期self.cal.setMinimumDate(QDate(1988,1,1))# 设置允许显示的最大日期self.cal.setMaximumDate(QDate(2088,1,1))# 绑定信号 槽self.cal.clicked.connect(self.showDate)# 以网格形式显示self.cal.setGridVisible(True)# 移动日历的位置  移动到左上角self.cal.move(20,20)# 设置窗口大小self.resize(400,400)# 设置标题self.setWindowTitle('日历演示')# 添加单击事件# 槽def showDate(self,date):# 显示当前选择的日期# 方式一  直接在事件里面获取# self.label.setText((date.toString('yyyy-MM-dd dddd')))# 方式二   直接通过日历,里面有个selcetedDate的方法获取self.label.setText((self.cal.selectedDate().toString("yyyy-MM-dd dddd")))# 防止其他脚本调用,只有单独运行,才会调用下面代码
if __name__ == '__main__':# app实例化,传参app = QApplication(sys.argv)# 创建对象main = MyCalendar()# 创建窗口main.show()# 进入主循环,调用exit方法,确保主循环安全退出sys.exit(app.exec_())

效果展示:

52.输入各种风格的日期和时间

在calendar_time文件夹里新建DateTimeEdit1.py文件,执行代码:

"""
输入各种风格的日期和时间QDateTimeEdit
"""
# 只想显示当前所设置的时间和日期import sys,math
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *class DateTimeEdit1(QWidget):def __init__(self):super(DateTimeEdit1, self).__init__()self.initUI()# 编写初始化方法,规范代码,初始化写在一个方法里def initUI(self):# 设置窗口标题self.setWindowTitle('设置不同风格的日期和时间')# 设置窗口尺寸self.resize(200,150)# 创建垂直布局layout = QVBoxLayout()# 创建QDateTimeEdit控件# 第一个dateTimeEdit1 = QDateTimeEdit()# 第二个可以传入当前的时间和日期dateTimeEdit2 = QDateTimeEdit(QDateTime.currentDateTime())# 创建单独显示日期的控件# 第三个dateEdit = QDateTimeEdit(QDate.currentDate())# 创建单独显示时间的控件# 第四个timeEdit = QDateTimeEdit(QTime.currentTime())# 分别给这是四个控件设置显示日期或者时间的格式dateTimeEdit1.setDisplayFormat("yyyy-MM-dd HH:mm:ss")dateTimeEdit2.setDisplayFormat("yyyy/MM/dd HH-mm-ss")dateEdit.setDisplayFormat("yyyy.MM.dd")timeEdit.setDisplayFormat("HH:mm:ss")# 把控件添加到垂直布局里layout.addWidget(dateTimeEdit1)layout.addWidget(dateTimeEdit2)layout.addWidget(dateEdit)layout.addWidget(timeEdit)# 应用于垂直布局self.setLayout(layout)# 防止其他脚本调用,直接运行此脚本,才会调用下面的代码
if __name__ == '__main__':# app实例化,并传参app = QApplication(sys.argv)# 创建对象main = DateTimeEdit1()# 创建窗口main.show()# 进入主循环,调用exit方法,确保主循环安全退出sys.exit(app.exec_())

效果展示:

拓展:

日期和时间控件的高级操作

"""
输入各种风格的日期和时间QDateTimeEdit
"""
# 只想显示当前所设置的时间和日期import sys,math
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *class DateTimeEdit1(QWidget):def __init__(self):super(DateTimeEdit1, self).__init__()self.initUI()# 编写初始化方法,规范代码,初始化写在一个方法里def initUI(self):# 设置窗口标题self.setWindowTitle('设置不同风格的日期和时间')# 设置窗口尺寸self.resize(200,150)# 创建垂直布局layout = QVBoxLayout()# 创建QDateTimeEdit控件# 第一个dateTimeEdit1 = QDateTimeEdit()# 第二个可以传入当前的时间和日期dateTimeEdit2 = QDateTimeEdit(QDateTime.currentDateTime())# 创建单独显示日期的控件# 第三个dateEdit = QDateTimeEdit(QDate.currentDate())# 创建单独显示时间的控件# 第四个timeEdit = QDateTimeEdit(QTime.currentTime())# 创建button控件,目的:通过点击button获取当前的时间self.btn = QPushButton('获取日期和时间')# 分别给这是四个控件设置显示日期或者时间的格式dateTimeEdit1.setDisplayFormat("yyyy-MM-dd HH:mm:ss")dateTimeEdit2.setDisplayFormat("yyyy/MM/dd HH-mm-ss")dateEdit.setDisplayFormat("yyyy.MM.dd")timeEdit.setDisplayFormat("HH:mm:ss")# 把控件添加到垂直布局里layout.addWidget(dateTimeEdit1)layout.addWidget(dateTimeEdit2)layout.addWidget(dateEdit)layout.addWidget(timeEdit)#   把拓展里的按钮添加到布局里面layout.addWidget(self.btn)# 应用于垂直布局self.setLayout(layout)# 拓展# 给dateTimeEdit1设置最大最小值# QDate.currentDate().addDays(-365) 表示回退当前时间的365天# dateTimeEdit1.setMinimumDate(QDate.currentDate().addDays(-365))# QDate.currentDate().addDays(365)   表示增加当前时间的365天# dateTimeEdit1.setMinimumDate(QDate.currentDate().addDays(365))# 给dateTimeEdit2添加日历控件dateTimeEdit2.setCalendarPopup(True)# 把这三个槽都绑定到第一个控件上dateTimeEdit1.dateChanged.connect(self.onDateChanged)dateTimeEdit1.timeChanged.connect(self.onTimeChanged)dateTimeEdit1.dateTimeChanged.connect(self.onDateTimeChanged)# 如何来获取设置的日期和时间# 绑定 信号  槽self.btn.clicked.connect(self.onButtonClick)# 设置当前时间为dateTimeEdit1的时间self.dateTimeEdit = dateTimeEdit1# 事件# 日期变化  时间变化  日期时间变化# 槽# 日期变化def onDateChanged(self,date):print(date)# 时间变化def onTimeChanged(self,time):print(time)# 日期和时间变化def onDateTimeChanged(self,datetime):print(datetime)# 添加单击的槽def onButtonClick(self):# 获取当前日期时间datetime = self.dateTimeEdit.dateTime()print(datetime)# 获得最大日期print(self.dateTimeEdit.maximumDate())# 获得最大日期和时间print(self.dateTimeEdit.maximumDateTime())# 获得最小日期print(self.dateTimeEdit.minimumDate())# 获得最小日期和时间print(self.dateTimeEdit.minimumDateTime())# 防止其他脚本调用,直接运行此脚本,才会调用下面的代码
if __name__ == '__main__':# app实例化,并传参app = QApplication(sys.argv)# 创建对象main = DateTimeEdit1()# 创建窗口main.show()# 进入主循环,调用exit方法,确保主循环安全退出sys.exit(app.exec_())

效果展示:

53.创建和使用菜单

在menu_toolbar_statusbar文件夹里新建Menu.py文件,执行代码:

"""
创建和使用菜单
"""import sys,math
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *class Menu(QMainWindow):def __init__(self):super(Menu, self).__init__()# 设置窗口尺寸self.resize(300,200)# 获取菜单栏bar = self.menuBar()# 给菜单栏添加 "文件"file = bar.addMenu("文件")# 给文件添加动作 "新建"# 第一种添加方式file.addAction("新建")# 第二种添加方式  通过QAction# 添加动作 "保存"save = QAction("保存",self)# 给保存添加快捷键save.setShortcut("Ctrl + S")# 把"保存"动作添加到"文件"下面file.addAction(save)# 把save触发连接槽save.triggered.connect(self.process)# 给菜单栏添加"编辑"菜单edit = bar.addMenu("Edit")# 给"编辑"添加"复制"动作edit.addAction("copy")# 给"编辑"添加"粘贴"动作edit.addAction("paste")# 创建"退出"动作quit =QAction("Quit",self)# 把"退出"添加到"文件"下面file.addAction(quit)# 给动作添加事件def process(self,a):print(self.sender().text())# 直接运行此脚本,才会调用下面代码
if __name__ == '__main__':# app实例化,并传参app =   QApplication(sys.argv)# 创建对象main = Menu()# 创建窗口main.show()# 进入主循环,调用exit方法,确保主循环安全退出sys.exit(app.exec_())

效果展示:

54.创建和使用工具栏

在menu_toolbar_statusbar文件夹里新建Toolbar.py文件,执行代码:

"""
创建和使用工具栏三种显示状态   显示图标  显示文本   显示图标和文本
图标和文本的关系:上下  左右使用addToolBar添加
self.addToolBar()   传参  传工具栏的名字    可以创建任意多个工具栏     会从左向右排列工具栏默认按钮:只显示图标,将文本作为悬停提示展示
"""
import sys,math
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *class Toolbar(QMainWindow):def __init__(self):super(Toolbar, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('工具栏例子')# 设置尺寸大小self.resize(300,200)# 创建工具栏tb1 = self.addToolBar("File")# 往工具栏添加按钮,添加动作# 添加图标,添加文本# self  表示放在当前的窗口上# 工具栏默认按钮:只显示图标,将文本作为悬停提示展示new = QAction(QIcon('../controls/images/5.png'),"new",self)# 添加new动作tb1.addAction(new)# 在工具栏添加第二个按钮open = QAction(QIcon('../controls/images/4.jpg'),"open",self)# 添加open动作tb1.addAction(open)# 在工具栏添加第三个按钮save = QAction(QIcon('../controls/images/3.ico'),"save",self)tb1.addAction(save)# 设置既显示图标又显示文本# 文本在图标的右侧显示# tb1.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)# 文本在图标的下侧显示tb1.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)# 只显示文本# tb1.setToolButtonStyle(Qt.ToolButtonTextOnly)# 默认情况下只显示图标# 给tb1添加动作 用来显示按了哪一个按钮# 绑定信号 槽tb1.actionTriggered.connect(self.toolbtnpressed)# 让有的按钮只显示图标,有的按钮只显示文本# 通过创建多个工具条,一是可以将同类别的控件放在一起,二是可以控制每个工具栏相关的属性# 创建工具栏tb2 = self.addToolBar("File1")# 往工具栏添加动作new1 = QAction(QIcon('../controls/images/5.png'), "new1", self)# 添加new1动作tb2.addAction(new1)tb2.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)tb2.actionTriggered.connect(self.toolbtnpressed)# 槽方法# 显示按下的哪个按钮def toolbtnpressed(self,a):print("按下的工具栏按钮是",a.text())# 直接运行此脚本,才会执行下面代码
if __name__ == '__main__':# app实例化,并传参app = QApplication(sys.argv)# 创建对象main = Toolbar()# 创建窗口main.show()# 进入主循环,调用exit方法 ,确保主循环安全退出sys.exit(app.exec_())

效果展示:

55.创建和使用状态栏

在menu_toolbar_statusbar文件夹里新建StatusBar.py文件,执行代码:

"""
创建和使用状态栏用于显示状态信息"""
# 添加菜单 点击菜单会在状态栏里面显示五秒的信息,然后自动的消失
import sys,math
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *class StatusBar(QMainWindow):def __init__(self):super(StatusBar, self).__init__()self.initUI()# 编写初始化的方法,规范代码def initUI(self):# 设置窗口标题self.setWindowTitle('状态栏演示')# 设置尺寸self.resize(300,200)# 创建状态栏self.statusBar = QStatusBar()# 设置状态self.setStatusBar(self.statusBar)# 获得菜单栏bar = self.menuBar()# 在菜单栏里面添加"文件"菜单file = bar.addMenu("File")# 给文件菜单添加动作  给"文件"菜单添加子菜单file.addAction("show")# 添加触发的动作file.triggered.connect(self.processTrigger)# 放置一个中心控件self.setCentralWidget(QTextEdit())# 槽方法def processTrigger(self,q):if q.text() == "show":# 文本显示五秒钟,自动关闭self.statusBar.showMessage(q.text() + "菜单被点击了",5000)# 防止别的脚本调用,只有单独执行此脚本时,才会调用下面代码
if __name__ == '__main__':# app实例化,并传参app = QApplication(sys.argv)# 创建对象main = StatusBar()# 创建窗口main.show()# 执行主循环,调用exit方法,确保主循环安全退出sys.exit(app.exec_())

效果展示:

56.使用打印机

如何将数据输出到打印机

新建printer文件,在printer文件夹里新建PrintSupport.py文件,执行代码:

"""
使用打印机
如何将数据输出到打印机
QtPrintSupport
以图像的形式输出
"""
# 创建button,点击button,将button里面的内容输出到打印机import sys
from PyQt5 import QtGui,QtWidgets,QtPrintSupport
from PyQt5.QtWidgets import *class PrintSupport(QMainWindow):def __init__(self):super(PrintSupport, self).__init__()# 设置位置self.setGeometry(500,200,300,300)# 创建button控件self.button = QPushButton('打印QTextEdit控件中的内容',self)# 设置按钮的位置self.button.setGeometry(20,20,260,30)# 创建文本控件self.editor = QTextEdit('默认文本',self)#设置文本控件的位置self.editor.setGeometry(20,60,260,200)# 绑定信号 槽self.button.clicked.connect(self.print)# 槽方法def print(self):# 创建打印对象printer = QtPrintSupport.QPrinter()# 获得画painter = QtGui.QPainter()# 把数据绘制到printer里面# 将绘制的目标重定向到打印机painter.begin(printer)# 获得editor屏幕的内容screen = self.editor.grab()# 设置绘制位置painter.drawPixmap(10,10,screen)painter.end()print("pass")# 直接运行该脚本,才会执行下面代码
if __name__ == '__main__':app = QtWidgets.QApplication(sys.argv)gui = PrintSupport()gui.show()app.exec_()

效果展示:

57.显示打印对话框

在printer文件夹里新建PrintDialog.py文件,执行代码:

"""
显示打印对话框
"""# 放置文本对话框,打开文档,显示页面设置对话框和打印文档对象框
import sys
from PyQt5.QtWidgets import QWidget,QApplication,QPushButton,QTextEdit,QFileDialog,QDialog
from PyQt5.QtPrintSupport import QPageSetupDialog,QPrintDialog,QPrinterclass PrintDialog(QWidget):def __init__(self):super(PrintDialog, self).__init__()self.printer = QPrinter()self.initUI()def initUI(self):# 设置位置self.setGeometry(300,300,500,400)# 设置窗口标题self.setWindowTitle('打印对话框')# 创建文本框组件self.editor = QTextEdit(self)# 设置位置self.editor.setGeometry(20,20,300,270)# 创建button1控件# 打开按钮self.openButton = QPushButton('打开文件',self)# 设置位置self.openButton.move(350,20)# 创建button2控件# 设置按钮self.settingsButton = QPushButton('打印设置',self)# 设置位置self.settingsButton.move(350,50)# 创建button3控件# 打印按钮self.printButton = QPushButton('打印文档',self)# 设置位置self.printButton.move(350,80)# 绑定信号 槽self.openButton.clicked.connect(self.openFile)self.settingsButton.clicked.connect(self.showSettingDialog)self.printButton.clicked.connect(self.showPrintDialog)# 槽方法# 打开文件def openFile(self):fname = QFileDialog.getOpenFileName(self,'打开文本文件','./')if fname[0]:with open(fname[0],'r',encoding='utf-8',errors='ignore') as f:self.editor.setText(f.read())# 显示打印设置对话框def showSettingDialog(self):printDialog = QPageSetupDialog(self.printer,self)printDialog.exec()# 显示打印对话框def showPrintDialog(self):printdialog = QPrintDialog(self.printer,self)if QDialog.Accepted == printdialog.exec():self.editor.print(self.printer)if __name__ == '__main__':app = QApplication(sys.argv)gui = PrintDialog()gui.show()sys.exit(app.exec_())

效果展示:

58.显示二维表数据(QTableView控件)

新建table_tree文件夹,在table_tree文件夹里新建TableView.py文件,执行代码:

"""
显示二维表数据(QTableView控件)对于QTableView控件,它的数据源是Model需要创建QTableView实例和一个数据源(Model),然后将两者关联
MVC:Model  Viewer  Controller
MVC的目的是将后端的数据和前端页面的耦合度降低"""
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *class TableView(QWidget):def __init__(self):super(TableView, self).__init__()# 设置窗口标题self.setWindowTitle("QTableView表格视图控件演示")# 设置窗口尺寸self.resize(500,300)# 创建QStandardItemModel对象  4行3列self.model = QStandardItemModel(4,3)# 设置字段self.model.setHorizontalHeaderLabels(['id','姓名','年龄'])# 创建QTableView控件self.tableview = QTableView()# 关联模型self.tableview.setModel(self.model)# 添加数据item11 = QStandardItem('10')itme12 = QStandardItem('杰克')item13 = QStandardItem('18')#  第一行第一列self.model.setItem(0,0,item11)#  第一行第二列self.model.setItem(0,1,itme12)#  第一行第三列self.model.setItem(0,2,item13)item31 = QStandardItem('99')itme32 = QStandardItem('酒桶')item33 = QStandardItem('21')#  第一行第一列self.model.setItem(2, 0, item31)#  第一行第二列self.model.setItem(2, 1, itme32)#  第一行第三列self.model.setItem(2, 2, item33)# 创建垂直布局layout = QVBoxLayout()# 把控件添加到布局里layout.addWidget(self.tableview)# 应用于垂直布局self.setLayout(layout)if __name__ == '__main__':app = QApplication(sys.argv)table = TableView()table.show()sys.exit(app.exec_())

效果展示:

59.显示列表数据(QListView控件)

在table_tree文件夹里新建ListView.py文件,执行代码:

"""
显示列表数据 (QListView控件)
"""import sys
from PyQt5.QtWidgets import QApplication,QWidget,QVBoxLayout,QListView,QMessageBox
from PyQt5.QtCore import QStringListModelclass ListViewDemo(QWidget):def __init__(self ,parent = None):super(ListViewDemo, self).__init__(parent)# 设置窗口标题self.setWindowTitle("QListView例子")# 设置窗口尺寸self.resize(300,270)# 创建垂直布局layout = QVBoxLayout()# 创建QListViewlistview = QListView()# 创建字符串列表的模型# model相当于一个数据源listModel = QStringListModel()# 创建数据源self.list = ["列表项1","列表项2","列表项3"]# 把模型和列表绑定listModel.setStringList(self.list)listview.setModel(listModel)listview.clicked.connect(self.clicked)# 把控件添加到布局里layout.addWidget(listview)# 应用于垂直布局self.setLayout(layout)# 槽def clicked(self,item):QMessageBox.information(self,"QListView","您选择了:" + self.list[item.row()])if __name__ == '__main__':app = QApplication(sys.argv)win = ListViewDemo()win.show()sys.exit(app.exec_())

效果展示:

60.扩展的列表控件(QListWidget)

在table_tree文件夹里新建ListWidget.py文件,执行代码:

"""
扩展的列表控件(QListWidget)
QListWidget是QListView的子类
支持MVC 和 VMC
"""
import sys
from PyQt5.QtWidgets import *class ListWidgetDemo(QMainWindow):def __init__(self,parent= None):super(ListWidgetDemo, self).__init__(parent)# 设置窗口标题self.setWindowTitle('QListWidget 例子')# 设置窗口的尺寸self.resize(300,270)# 创建QListWidget控件self.listwidget = QListWidget()# 设置的尺寸# self.listwidget.resize(300,120)# 给QListWidget控件添加数据项self.listwidget.addItem("item1")self.listwidget.addItem("item2")self.listwidget.addItem("item3")self.listwidget.addItem("item4")self.listwidget.addItem("item5")# 给QListWidget控件设置标题self.listwidget.setWindowTitle("demo")# 设为中心窗口self.setCentralWidget(self.listwidget)# 连接信号 槽self.listwidget.itemClicked.connect(self.clicked)# 槽方法def clicked(self,Index):QMessageBox.information(self,"QListWidget","您选择了:" + self.listwidget.item(self.listwidget.row(Index)).text())if __name__ == '__main__':app = QApplication(sys.argv)win = ListWidgetDemo()win.show()sys.exit(app.exec_())

效果展示:

61.扩展的表格控件(QTableWidget)

在table_tree文件夹里新建TableWidget.py文件,执行代码:

"""
扩展的表格控件(QTableWidget)
是在QTableView上面进行扩展每一个Cell(单元格)是一个QTableWidgetItem
"""
import sys
from PyQt5.QtWidgets import (QWidget, QTableWidget, QHBoxLayout, QApplication, QTableWidgetItem, QAbstractItemView)class TableWidgetDemo(QWidget):def __init__(self):super(TableWidgetDemo, self).__init__()self.initUI()def initUI(self):# 设置窗口标题self.setWindowTitle("QTableWidget演示")# 设置窗口尺寸self.resize(430,230)# 创建一个水平布局layout = QHBoxLayout()# 创建一个QTableWidget控件tableWidget = QTableWidget()# 设置行数tableWidget.setRowCount(4)# 设置列数tableWidget.setColumnCount(3)# 把控件添加到布局里layout.addWidget(tableWidget)# 设水平表头tableWidget.setHorizontalHeaderLabels(["姓名","年龄","籍贯"])# 创建第一个QTableWidgetItem对象nameItem = QTableWidgetItem("小明")# 把nameItem放置在tablewidget里面# 放置在第一行第一列tableWidget.setItem(0,0,nameItem)# 创建第二个QTableWidgetItem对象ageItem = QTableWidgetItem("22")# 把nameItem放置在tablewidget里面# 放置在第一行第二列tableWidget.setItem(0, 1, ageItem)# 创建第三个QTableWidgetItem对象jiguanItem = QTableWidgetItem("天津")# 把nameItem放置在tablewidget里面# 放置在第一行第三列tableWidget.setItem(0, 2, jiguanItem)# 禁止编辑tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)# 让光标整行显示tableWidget.setSelectionBehavior(QAbstractItemView.SelectRows)# 调整列  根据内容调整tableWidget.resizeColumnsToContents()# 调整行  根据内容调整tableWidget.resizeRowsToContents()# 隐藏水平的头# tableWidget.horizontalHeader().setVisible(False)# 隐藏垂直的头# tableWidget.verticalHeader().setVisible(False)# 设置垂直的头tableWidget.setVerticalHeaderLabels(["a","b"])# 隐藏表格线tableWidget.setShowGrid(False)# 应用于水平布局self.setLayout(layout)if __name__ == '__main__':app = QApplication(sys.argv)example = TableWidgetDemo()example.show()sys.exit(app.exec_())

效果展示:

62.在单元格中放置控件

在table_tree文件夹里新建PlaceControlInCell.py文件,执行代码:

"""
在单元格放置控件
setItem:将文本放到单元格中
setCellWidget:将控件放到单元格
setStyleSheet:设置控件的样式(QSS)"""
import sys
from PyQt5.QtWidgets import (QWidget,QTableWidget,QHBoxLayout,QApplication,QTableWidgetItem,QComboBox,QPushButton)class PlaceControlInCell(QWidget):def __init__(self):super(PlaceControlInCell, self).__init__()self.initUI()def initUI(self):# 设置窗口标题self.setWindowTitle("在单元格中放置控件")# 设置窗口尺寸self.resize(430,300)# 创建水平布局layout = QHBoxLayout()# 创建一个QTableWiddget控件tableWidget = QTableWidget()# 为QTableWiddget指定行tableWidget.setRowCount(4)# 为QTableWiddget指定列tableWidget.setColumnCount(3)# 把控件添加到布局里layout.addWidget(tableWidget)# 为 tableWidget 添加表格的头tableWidget.setHorizontalHeaderLabels(['姓名','性别','体重(kg)'])# 创建 QTableWidgetItem# 放置文本textItem = QTableWidgetItem('小明')# 把文本项添加到tablewidget里面# setItem 一般三个参数,行 列 传哪# 将这个文本放到第一行第一列tableWidget.setItem(0,0,textItem)# 创建QComboBox对象combox = QComboBox()# 给combox添加两个选项combox.addItem('男')combox.addItem('女')# QSS  类似于web里面的CSS  Qt StyleSheet# 设置所有的combox控件,让它的边距是3pxcombox.setStyleSheet('QComboBox{margin:3px};')# 在单元格放置控件# 防止第一行第二列tableWidget.setCellWidget(0,1,combox)# 创建一个button组件modifyButton = QPushButton('修改')# 默认是按下状态modifyButton.setDown(True)# 使用QSS设置样式  设置所有的QPushButton控件,让它的边距是3pxmodifyButton.setStyleSheet('QPushButton{margin:3px};')# 在单元格放置控件tableWidget.setCellWidget(0,2,modifyButton)# 应用于水平布局self.setLayout(layout)if __name__ == '__main__':app = QApplication(sys.argv)example  =PlaceControlInCell()example.show()sys.exit(app.exec_())

效果展示:

63.在表格中快速定位到特定的样式

在table_tree文件夹里新建DataLocation.py文件,执行代码:

"""
在表格中快速定位到特定的样式1. 数据的定位  findItems 返回一个列表   如果没查到,列表为空
2.如果找到了满足条件的单元格,会定位到单元格所在的行 setSliderPosition(row)# 三个步骤
1.在表格里面显示很多的数据
2.通过findItems来找到所有满足条件的单元格
3.通过setSliderPosition(row)定位到满足条件的这一行
"""import sysfrom PyQt5 import QtCore
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import QColor,QBrushclass DataLocation(QWidget):def __init__(self):super(DataLocation, self).__init__()self.initUI()def initUI(self):# 设置窗口标题self.setWindowTitle('QTableWidget 例子')# 设置窗口尺寸self.resize(600,800)# 创建水平布局layout = QHBoxLayout()# 创建QTableWidget控件tableWidget = QTableWidget()# 给tableWidget设置行tableWidget.setRowCount(40)#给tableWidget设置列tableWidget.setColumnCount(4)# 将控件添加到布局里layout.addWidget(tableWidget)# 对行循环 对列循环for i in range(40):for j in range(4):# 得到每个单元格的内容itemContent = '(%d,%d)' % (i,j)# 把内容放到表格中tableWidget.setItem(i,j,QTableWidgetItem(itemContent))# 搜索满足条件的Celltext = '(13,1)'# 精确搜索items = tableWidget.findItems(text,QtCore.Qt.MatchExactly)if len(items) > 0:items = items[0]# 设置背景色items.setBackground(QBrush(QColor(0,255,0)))items.setForeground(QBrush(QColor(255,0,0)))# 获得当前项所在的行row = items.row()# 定位到指定的行# verticalScrollBar 获得滚动条tableWidget.verticalScrollBar().setSliderPosition(row)# 搜索满足条件的Celltext = '(1'# MatchStartsWit 以..开头items = tableWidget.findItems(text, QtCore.Qt.MatchStartsWith)if len(items) > 0:items = items[0]# 设置背景色items.setBackground(QBrush(QColor(0, 255, 0)))items.setForeground(QBrush(QColor(255, 0, 0)))# 获得当前项所在的行row = items.row()# 定位到指定的行# verticalScrollBar 获得滚动条tableWidget.verticalScrollBar().setSliderPosition(row)# 应用于布局self.setLayout(layout)if __name__ == '__main__':# app实例化 传参app = QApplication(sys.argv)# 创建对象example = DataLocation()# 创建窗口example.show()# 进入主循环sys.exit(app.exec_())

效果展示:

64.设置单元格字体和颜色

在table_tree文件夹里新建CellFontAndColor.py文件,执行代码:

"""
设置单元格字体和颜色
"""import sys
from PyQt5.QtWidgets import (QWidget,QTableWidget,QHBoxLayout,QApplication,QTableWidgetItem)
from PyQt5.QtGui import QBrush,QColor,QFontclass CellFontAndColor(QWidget):def __init__(self):super(CellFontAndColor, self).__init__()self.initUI()def initUI(self):# 设置窗口标题self.setWindowTitle("设置单元格字体和颜色")# 设置窗口的尺寸self.resize(600,300)# 创建水平布局layout = QHBoxLayout()# 创建QTableWidget控件tableWidget = QTableWidget()# 设置tableWidget的行tableWidget.setRowCount(4)# 设置tableWidget的列tableWidget.setColumnCount(3)# 把控件放置在布局里layout.addWidget(tableWidget)# 设水平表头tableWidget.setHorizontalHeaderLabels(['姓名','性别','体重(kg)'])# 创建QTableWidgetItem控件newItem = QTableWidgetItem('水手')# 字号 字体newItem.setFont(QFont('Times',14,QFont.Black))# 设置字颜色newItem.setForeground(QBrush(QColor(255,0,0)))# 添加到第一行第一列tableWidget.setItem(0,0,newItem)# 创建QTableWidgetItem控件newItem = QTableWidgetItem('大海')# 设置字的颜色newItem.setForeground(QBrush(QColor(255,200,0)))# 设置背景色newItem.setBackground(QBrush(QColor(0,0,220)))# 添加到第一行第二列tableWidget.setItem(0,1,newItem)# 创建QTableWidgetItem控件newItem = QTableWidgetItem('你好')# 设置字的颜色newItem.setFont(QFont('Times', 25, QFont.Black))newItem.setForeground(QBrush(QColor(125, 50, 0)))# 设置背景色newItem.setBackground(QBrush(QColor(0, 0, 20)))# 添加到第一行第二列tableWidget.setItem(0, 2, newItem)# 应用于水平布局self.setLayout(layout)if __name__ == '__main__':app = QApplication(sys.argv)example = CellFontAndColor()example.show()sys.exit(app.exec_())

效果展示:

65.按列排序

在table_tree文件夹里新建ColumnSort.py文件,执行代码:

"""
按列排序1.按那一列排序
2.排序类型  升序或降序sortItems(columnIdex,orderType)
"""
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *class ColumnSort(QWidget):def __init__(self):super(ColumnSort, self).__init__()self.initUI()def initUI(self):# 设置窗口标题self.setWindowTitle('按列排序')# 设置窗口尺寸self.resize(600,400)# 创建垂直布局layout = QVBoxLayout()# 创建QTableWdiget控件self.tableWidget  = QTableWidget()# 设置行数self.tableWidget.setRowCount(4)# 设置列数self.tableWidget.setColumnCount(3)# 把控件添加到布局里layout.addWidget(self.tableWidget)# 设置水平表头self.tableWidget.setHorizontalHeaderLabels(['姓名','性别','体重(kg)'])# 创建QTableWidgetItem控件newItem = QTableWidgetItem('张三')# 添加到第一行第一列self.tableWidget.setItem(0,0,newItem)# 创建QTableWidgetItem控件newItem = QTableWidgetItem('男')# 添加到第一行第二列self.tableWidget.setItem(0, 1, newItem)# 创建QTableWidgetItem控件newItem = QTableWidgetItem('178')# 添加到第一行第三列self.tableWidget.setItem(0, 2, newItem)# 创建QTableWidgetItem控件newItem = QTableWidgetItem('李四')# 添加到第二行第一列self.tableWidget.setItem(1, 0, newItem)# 创建QTableWidgetItem控件newItem = QTableWidgetItem('男')# 添加到第二行第二列self.tableWidget.setItem(1, 1, newItem)# 创建QTableWidgetItem控件newItem = QTableWidgetItem('172')# 添加到第二行第三列self.tableWidget.setItem(1, 2, newItem)# 创建QTableWidgetItem控件newItem = QTableWidgetItem('花花')# 添加到第三行第一列self.tableWidget.setItem(2, 0, newItem)# 创建QTableWidgetItem控件newItem = QTableWidgetItem('女')# 添加到第三行第二列self.tableWidget.setItem(2, 1, newItem)# 创建QTableWidgetItem控件newItem = QTableWidgetItem('168')# 添加到第三行第三列self.tableWidget.setItem(2, 2, newItem)# 添加button按钮self.button = QPushButton('排序')# 绑定 信号 槽self.button.clicked.connect(self.order)# 把控件放到布局里layout.addWidget(self.button)# 设置当前的排序类型   降序排列self.orderType = Qt.DescendingOrder# 应用于布局self.setLayout(layout)# 槽方法def order(self):# 如果当前排序是降序,则改为升序if self.orderType == Qt.DescendingOrder:self.orderType = Qt.AscendigOrderelse:# 如果是升序,改成降序self.orderType = Qt.DescendingOrder# 排序self.tableWidget.sortItems(2,self.orderType)if __name__ == '__main__':app = QApplication(sys.argv)main = ColumnSort()# 创建窗口main.show()# 创建主程序sys.exit(app.exec_())

效果展示:

ps:windows上,因为DescendingOrder方法问题,只能显示上图效果,点击排序按钮后,退出。待后续解决。

66.设置单元格的文本对齐方式

在table_tree文件夹里新建CellTextAlignment.py文件,执行代码:

"""
设置单元格的文本对齐方式使用setTextAlignment方法
里面有一些常量  Qt.AlignRight  Qt.AlignBottom"""
import sys
from PyQt5.QtWidgets import (QWidget,QTableWidget,QHBoxLayout,QApplication,QTableWidgetItem)
from PyQt5.QtCore import  Qtclass CellTextAlignment(QWidget):def __init__(self):super(CellTextAlignment, self).__init__()self.initUI()def initUI(self):# 设置窗口标题self.setWindowTitle('设置单元格的文本对齐方式')# 设置尺寸self.resize(430,230)# 创建水平布局layout = QHBoxLayout()# 创建QTableWidget控件tableWidget = QTableWidget()# 设置行数tableWidget.setRowCount(4)# 设置列数tableWidget.setColumnCount(3)# 把控件添加到布局里layout.addWidget(tableWidget)# 设置水平表头tableWidget.setHorizontalHeaderLabels(['姓名','性别','体重(kg)'])# 添加字段# 创建QTableWidgetItem控件newItem = QTableWidgetItem('水生')# 设置文本为右对齐  默认单元格的顶端显示  可以设置为底端newItem.setTextAlignment(Qt.AlignRight | Qt.AlignBottom)# 给tableWidget添加newItem字段   此时表内是空的#  把newItem字段添加到第一行第一列tableWidget.setItem(0,0,newItem)# 添加字段# 创建QTableWidgetItem控件newItem = QTableWidgetItem('28')# 设置文本为中心对齐  上下左右都对称    Qt.AlignBottom未起作用newItem.setTextAlignment(Qt.AlignCenter | Qt.AlignBottom)# 给tableWidget添加newItem字段   此时表内是空的#  把newItem字段添加到第一行第二列tableWidget.setItem(0, 1, newItem)# 添加字段# 创建QTableWidgetItem控件newItem = QTableWidgetItem('178')# 设置文本为右对齐  newItem.setTextAlignment(Qt.AlignRight)# 给tableWidget添加newItem字段   此时表内是空的#  把newItem字段添加到第一行第三列tableWidget.setItem(0, 2, newItem)# 应用于水平布局self.setLayout(layout)# 单独执行此脚本,才会运行下面的代码
if __name__ == '__main__':# app实例化,并传参app = QApplication(sys.argv)# 创建对象example = CellTextAlignment()# 创建窗口example.show()# 进入主循环,调用exit方法,确保主循环顺利退出sys.exit(app.exec_())

效果展示:

67.合并单元格

在table_tree文件夹里新建Span.py文件,执行代码:

"""
合并单元格
setSpan(row,col,要合并的行数,要合并的列数)"""
import sys
from PyQt5.QtWidgets import (QWidget,QTableWidget,QHBoxLayout,QApplication,QTableWidgetItem)class Span(QWidget):def __init__(self):super(Span, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('合并单元格')self.resize(430,230)# 创建水平布局layout = QHBoxLayout()# 创建表格控件tableWidget = QTableWidget()# 设置表格的行数tableWidget.setRowCount(4)# 设置表格的列数tableWidget.setColumnCount(3)# 把表格控件添加到布局里layout.addWidget(tableWidget)# 创建水平表头tableWidget.setHorizontalHeaderLabels(['姓名','年龄','身高'])# 创建字段newItem = QTableWidgetItem('大卫')# newItem添加到表格里 第一行第一列tableWidget.setItem(0,0,newItem)# 合并第一行第一列  ,合并3行,合并一列tableWidget.setSpan(0,0,3,1)# 创建字段newItem = QTableWidgetItem('18')# newItem添加到表格里  第一行第二列tableWidget.setItem(0, 1, newItem)# 合并第一行第二列   合并两行,合并一列tableWidget.setSpan(0,1,2,1)# 创建字段newItem = QTableWidgetItem('180')# newItem添加到表格里   第一行第三列tableWidget.setItem(0, 2, newItem)# 合并第一行第三列  合并4行 合并一列tableWidget.setSpan(0,2,4,1)# 创建字段newItem = QTableWidgetItem('测试')# newItem添加到表格里   第四行第一列tableWidget.setItem(3, 0, newItem)# 合并第四行第一  合并一行 合并两列tableWidget.setSpan(3, 0, 1, 2)# 应用于水平布局self.setLayout(layout)# 直接调用该脚本,执行下面代码
if __name__ == '__main__':# app实例化,并传参app = QApplication(sys.argv)# 创建对象main = Span()# 创建窗口main.show()# 进入主循环,调用exit方法,确保主循环安全退出sys.exit(app.exec_())

效果展示:

68.设置单元格的尺寸

在table_tree文件夹里新建CellSize.py文件,执行代码:

"""
设置单元格尺寸
"""
import sysfrom PyQt5.QtGui import QBrush, QColor, QFont
from PyQt5.QtWidgets import (QWidget,QTableWidget,QHBoxLayout,QApplication,QTableWidgetItem)class CellSize(QWidget):def __init__(self):super(CellSize, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('QTableWidget 例子')self.resize(530,300)# 创建水平布局layout  = QHBoxLayout()# 创建表格控件tableWidget = QTableWidget()# 设置表格控件的行tableWidget.setRowCount(4)# 设置表格控件的列tableWidget.setColumnCount(3)# 创建字段newItem = QTableWidgetItem('活力')# 设置字体  字体大小newItem.setFont(QFont('Times',20,QFont.Black))# 设置字体颜色newItem.setForeground(QBrush(QColor(30,113,150)))# 设置单元格背景newItem.setBackground(QBrush(QColor(30,82,30)))# 把字段添加到表格里  第一行第一列tableWidget.setItem(0,0,newItem)# 创建字段newItem = QTableWidgetItem('18')# 设置字体  字体大小newItem.setFont(QFont('Times', 40, QFont.Black))#改变行的高度   第一个参数是行  第二个参数是设定值   第一行  高度80tableWidget.setRowHeight(0,120)# 把字段添加到表格里    第一行第二列tableWidget.setItem(0, 1, newItem)# 创建字段newItem = QTableWidgetItem('167')# 设置字体  字体大小newItem.setFont(QFont('Times', 60, QFont.Black))# 改变第三行的高度   第三行  高度80tableWidget.setRowHeight(2,20)# 改变列的高度   第一个参数是列  第二个参数是设定值   第三列  宽度120tableWidget.setColumnWidth(2,160)# 把字段添加到表格里   第一行第三列tableWidget.setItem(0, 2, newItem)# 把表格控件添加到布局里layout.addWidget(tableWidget)#应用于表格控件self.setLayout(layout)# 直接执行此脚本,才会调用下面代码
if __name__ == '__main__':# app实例化,并传参app =QApplication(sys.argv)# 创建对象main = CellSize()# 创建窗口main.show()# 创建主循环,调用exit方法,确保主循环安全退出sys.exit(app.exec_())

效果展示:

69.在单元格中实现图文混排的效果

在table_tree文件夹里新建CellImageText.py文件,执行代码:

"""
在单元格中实现图文混排的效果
"""
# 让文本和图像 同时显示到一个单元格
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *class CellImageText(QWidget):def __init__(self):super(CellImageText, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('在单元格实现图文混排的效果')self.resize(800,300)# 创建水平布局layout = QHBoxLayout()# 创建全局表格控件self.tableWidget = QTableWidget()# 给表格控件设置行self.tableWidget.setRowCount(5)# 给表格控件设置列self.tableWidget.setColumnCount(4)# 给表格控件设置水平表头self.tableWidget.setHorizontalHeaderLabels(['姓名','性别','体重','显示图片'])# 创建字段# 添加QTableWidgetItem控件newItem = QTableWidgetItem('黎明')# 把字段控件放到表格控件里  第一行第一列self.tableWidget.setItem(0,0,newItem)newItem = QTableWidgetItem('男')# 把字段控件放到表格控件里  第一行第二列self.tableWidget.setItem(0, 1, newItem)newItem = QTableWidgetItem('18')# 把字段控件放到表格控件里  第一行第三列self.tableWidget.setItem(0, 2, newItem)# 第四列添加图片newItem = QTableWidgetItem(QIcon('../controls/images/5.png'),'背包')# 把newItem控件放到表格控件里 第一行第四列self.tableWidget.setItem(0,3,newItem)# 把表格控件添加到水平布局里面layout.addWidget(self.tableWidget)# 应用于水平布局self.setLayout(layout)if __name__ == '__main__':app =QApplication(sys.argv)main = CellImageText()main.show()sys.exit(app.exec_())

效果展示:

70.改变单元格中图片的尺寸

在table_tree文件夹里新建CellImageSize.py文件,执行代码:

"""
改变单元格中的图片尺寸setIconSize(QSize(width,height))
"""
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *class CellImageSize(QWidget):def __init__(self):super(CellImageSize, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('改变单元格中图片的尺寸')self.resize(800,600)# 创建水平布局layout = QHBoxLayout()# 创建表格控件tablewidget = QTableWidget()# 设置表格行tablewidget.setRowCount(5)# 设置表格列tablewidget.setColumnCount(3)# 设置表格内图像的尺寸tablewidget.setIconSize(QSize(200,80))# 设置水平表头tablewidget.setHorizontalHeaderLabels(['图片1','图片2','图片3'])# 让列的宽度和图片的宽度相同for i in range(3):tablewidget.setColumnWidth(i,200)# 让行的高度和图片的高度相同for i in range(5):tablewidget.setRowHeight(i,80)# 添加图片# 如果有15张图片for k in range(15):i = k / 3  # 行j = k % 3  # 列item = QTableWidgetItem()item.setIcon(QIcon('./images/00%s.jpg'% k))tablewidget.setItem(i,j,item)# 把表格控件添加到水平布局里layout.addWidget(tablewidget)# 应用于水平布局self.setLayout(layout)if __name__ == '__main__':app =QApplication(sys.argv)main = CellImageSize()main.show()sys.exit(app.exec_())

效果展示:

71.在表格中显示上下文菜单

在table_tree文件夹里新建TableWidgetContextMenu.py文件,执行代码:

"""
在表格中显示上下文1.如何弹出菜单
2.如何在满足条件的情况下弹出菜单 QMenu.exec_"""
# 特定单元格点击鼠标右键弹出菜单import sysfrom PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (QMenu,QPushButton,QWidget,QTableWidget,QHBoxLayout,QApplication,QTableWidgetItem,QHeaderView)class TableWidgetContextMenu(QWidget):def __init__(self):super(TableWidgetContextMenu, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('在表格中显示上下文菜单')self.resize(500,300)# 创建水平布局layout = QHBoxLayout()# 创建全局的表格控件self.tableWidget = QTableWidget()# 表格设置行self.tableWidget.setRowCount(5)# 表格设置列self.tableWidget.setColumnCount(3)# 把表格添加到水平布局里layout.addWidget(self.tableWidget)# 设置水平表格头self.tableWidget.setHorizontalHeaderLabels(['姓名','性别','体重'])# 添加字段newItem = QTableWidgetItem('张三')# 把字段添加到表格里 第一行第一列self.tableWidget.setItem(0,0,newItem)# 添加字段newItem = QTableWidgetItem('女')# 把字段添加到表格里  第一行第二列self.tableWidget.setItem(0, 1, newItem)# 添加字段newItem = QTableWidgetItem('28')# 把字段添加到表格里   第一行第三列self.tableWidget.setItem(0, 2, newItem)# 设置允许弹出菜单  单击右键响应事件self.tableWidget.setContextMenuPolicy(Qt.CustomContextMenu)# 将信号请求连接到一个槽self.tableWidget.customContextMenuRequested.connect(self.generateMenu)# 应用于水平布局self.setLayout(layout)# 槽方法def generateMenu(self,pos):# pos 为单击鼠标右键的坐标  相对于窗口# 鼠标右键单击前两行弹出菜单,单击第三行没响应print(pos)for i in self.tableWidget.selectionModel().selection().indexes():# 当前选中的行rowNum = i.row()# 如果选择的行索引小于2,弹出上下文菜单if rowNum < 2:menu = QMenu()item1 = menu.addAction("菜单项1")item2 = menu.addAction("菜单项2")item3 = menu.addAction("菜单项3")# 相对于窗口的坐标系转换为相对于屏幕的坐标系  映射到全局screePos = self.tableWidget.mapToGlobal(pos)print(screePos)# 被阻塞# action = menu.exec(pos)action = menu.exec(screePos)if action == item1:print('选择了第1个菜单项',self.tableWidget.item(rowNum,0).text(),self.tableWidget.item(rowNum,1).text(),self.tableWidget.item(rowNum,2).text())elif action == item1:print('选择了第2个菜单项',self.tableWidget.item(rowNum,0).text(),self.tableWidget.item(rowNum,1).text(),self.tableWidget.item(rowNum,2).text())elif action == item1:print('选择了第3个菜单项',self.tableWidget.item(rowNum,0).text(),self.tableWidget.item(rowNum,1).text(),self.tableWidget.item(rowNum,2).text())else:return
if __name__ == '__main__':app  = QApplication(sys.argv)main = TableWidgetContextMenu()main.show()sys.exit(app.exec_())

效果展示:

72.树控件(QTreeWidget)

在table_tree文件夹里新建BasicTreeWidget.py文件,执行代码:

"""
树控件(QTreeWidget)的基本用法
"""import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QIcon,QBrush,QColor
from PyQt5.QtCore import Qtclass BasicTreeWidget(QMainWindow):def __init__(self,parent= None):super(BasicTreeWidget, self).__init__(parent)self.setWindowTitle('树控件(QTreeWidget)的基本用法')self.resize(600,300)# 创建树控件self.tree = QTreeWidget()# 将树控件设为中心控件,充满整个屏幕self.setCentralWidget(self.tree)# 为树控件指定列数    让它显示两列# 每个都只能显示两列self.tree.setColumnCount(2)# 指定列标签self.tree.setHeaderLabels(['key','Value'])# 根节点# 类似于表格的创建字段root = QTreeWidgetItem(self.tree)# 将根阶段放置在第一列root.setText(0,'根节点')# 给根节点设置图标root.setIcon(0,QIcon('./images/000.jpg'))# 给第一列设置列宽self.tree.setColumnWidth(0,160)# 添加子节点1# 让子节点child1指向rootchild1 = QTreeWidgetItem(root)# 设置子节点第一列文本child1.setText(0,'子节点1')# 设置子节点第二列的文本child1.setText(1,"子节点1的数据")# 设置子节点第一列的图标child1.setIcon(0,QIcon('./images/001.jpg'))# 给子节点第一列添加复选框child1.setCheckState(0,Qt.Checked)# 设置子节点第二列的图标child1.setIcon(1, QIcon('./images/001.jpg'))# 添加子节点2# 让子节点child2指向rootchild2 = QTreeWidgetItem(root)# 设置子节点第一列文本child2.setText(0,'子节点2')# 设置子节点第一列设置图标child2.setIcon(0,QIcon('./images/006.jpg'))# 为子节点2再添加一个子节点# 让子节点chil2_指向子节点chil2child2_ = QTreeWidgetItem(child2)# 设置子节点第一列文本child2_.setText(0,'子节点2的子节点的第一列')# 设置子节点第一列文本child2_.setText(1, '子节点2的子节点的第二列')# 设置子节点第一列文本    由于设置了self.tree.setColumnCount(2),所以没有第三列# child2_.setText(2, '子节点2的子节点的第三列')# 给子节点的第一列设置图标child2_.setIcon(0,QIcon('./images/008.jpg'))# 给子节点的第二列设置图标child2_.setIcon(1, QIcon('./images/001.jpg'))# 将节点默认展开self.tree.expandAll()if __name__ == '__main__':app = QApplication(sys.argv)tree = BasicTreeWidget()tree.show()sys.exit(app.exec_())

效果展示:

73.为树节点添加响应事件

在table_tree文件夹里新建TreeEvent.py文件,执行代码:

"""
为树节点添加响应事件
"""
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *class TreeEvent(QMainWindow):def __init__(self,parent= None):super(TreeEvent, self).__init__(parent)self.setWindowTitle('为树节点添加响应事件')# 创建一个树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指向rootchild1 = QTreeWidgetItem(root)# 给子节点第一列设置文本child1.setText(0,"child1")# 给子节点第二列设置文本child1.setText(1,'1')# 创建子节点# 让子节点child2指向rootchild2 = QTreeWidgetItem(root)# 给子节点第一列设置文本child2.setText(0, "child2")# 给子节点第二列设置文本child2.setText(1, '2')# 创建子节点# 让子节点child3指向child2child3 = QTreeWidgetItem(child2)# 给子节点第一列设置文本child2.setText(0, "child3")# 给子节点第二列设置文本child2.setText(1, '3')# 将树设置为中心控件,充满整个屏幕# 这样在屏幕上就可以显示self.setCentralWidget(self.tree)# 为树添加节点,用单击信号self.tree.clicked.connect(self.onTreeClicked)# 槽方法def onTreeClicked(self,index):# 获得当前的单击项item = self.tree.currentItem()# 当前行print(index.row())# 输出当前单击节点的keyprint('key=%s,value=%s' % (item.text(0),item.text(1)))if __name__ == '__main__':app = QApplication(sys.argv)tree = TreeEvent()tree.show()sys.exit(app.exec_())

效果展示:

74.添加,修改和删除树控件中的节点

在table_tree文件夹里新建ModifyTree.py文件,执行代码:

"""
添加、修改和删除树控件中的节点
"""import sysfrom PyQt5.QtWidgets import *
from PyQt5.QtGui import *class ModifyTree(QWidget):def __init__(self,parent=None):super(ModifyTree, self).__init__(parent)self.setWindowTitle('TreeWidget  例子')self.resize(600,400)operatorLayout = QHBoxLayout()# 创建按钮控件addBtn = QPushButton('添加节点')updateBtn = QPushButton('修改节点')deleteBtn = QPushButton('删除节点')# 把控件添加到水平布局里operatorLayout.addWidget(addBtn)operatorLayout.addWidget(updateBtn)operatorLayout.addWidget(deleteBtn)# 把这三个按钮绑定到相应的槽上addBtn.clicked.connect(self.addNode)updateBtn.clicked.connect(self.updateNode)deleteBtn.clicked.connect(self.deleteNode)#  下行代码不需要,一次应用于布局就可以了# self.setLayout(operatorLayout)# 创建一个树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指向rootchild1 = QTreeWidgetItem(root)# 给子节点第一列设置文本child1.setText(0, "child1")# 给子节点第二列设置文本child1.setText(1, '1')# 创建子节点# 让子节点child2指向rootchild2 = QTreeWidgetItem(root)# 给子节点第一列设置文本child2.setText(0, "child2")# 给子节点第二列设置文本child2.setText(1, '2')# 创建子节点# 让子节点child3指向child2child3 = QTreeWidgetItem(child2)# 给子节点第一列设置文本child2.setText(0, "child3")# 给子节点第二列设置文本child2.setText(1, '3')# 将树设置为中心控件,充满整个屏幕# 这样在屏幕上就可以显示# self.setCentralWidget(self.tree)# 为树添加节点,用单击信号self.tree.clicked.connect(self.onTreeClicked)# 创建垂直布局mainLayout = QVBoxLayout(self)# 把按钮和树都放在垂直布局里# 此时按钮在水平布局里面mainLayout.addLayout(operatorLayout)# # 添加控件mainLayout.addWidget(self.tree)# 应用于垂直布局# self.setLayout(mainLayout)# 槽方法def onTreeClicked(self, index):# 获得当前的单击项item = self.tree.currentItem()# 当前行print(index.row())# 输出当前单击节点的keyprint('key=%s,value=%s' % (item.text(0), item.text(1)))# 槽方法def addNode(self):print('添加节点')# 获得当前的节点item = self.tree.currentItem()print(item)# 动态创建节点,指定父节点node = QTreeWidgetItem(item)# 创建node的第一列node.setText(0,'新节点')node.setText(1,'新值')# 创建node的第二列def updateNode(self):print('修改节点')# 获得当前的节点item = self.tree.currentItem()item.setText(0,'修改节点')item.setText(1,'值已经被修改')def deleteNode(self):print('删除节点')# 获得当前的节点item = self.tree.currentItem()# 通过循环  得到当前选中的节点# 获得不可见的根root = self.tree.invisibleRootItem()for item in self.tree.selectedItems():#  item.parent()和root只要有一个不为空,就不会出错(item.parent() or root).removeChild(item)if __name__ == '__main__':app = QApplication(sys.argv)main = ModifyTree()main.show()sys.exit(app.exec_())

效果展示:

75.QTreeView控件与系统定制模式

在table_tree文件夹里新建TreeView.py文件,执行代码:

"""
QTreeView控件与系统定制模式与QTreeWidget的不同点: QTreeWiget装载数据的方式是通过Model,比如Model里面的QDirModel 用来显示当前操作系统的目录结构
QTreeView  一般用于比较复杂的树
"""import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *if __name__ == '__main__':app = QApplication(sys.argv)# 创建QDirModel控件model = QDirModel()# 创建QTreeView控件tree = QTreeView()# 设置modeltree.setModel(model)# 把树作为一个窗口tree.setWindowTitle('QTreeView')# 设置树窗口的尺寸tree.resize(600,400)# 显示树tree.show()sys.exit(app.exec_())

效果展示:

76选项卡控件(QTableWidget)

新建containers文件夹,在containers文件夹里面新建TabWidgetDemo.py文件,执行代码:

"""
选项卡控件:QTabWidget目的:在屏幕上显示更多的控件  在页面中显示多页面
"""import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *class TabWidgetDemo(QTabWidget):def __init__(self,parent=None):super(TabWidgetDemo, self).__init__(parent)self.setWindowTitle('选项卡控件:QTabWidget')self.resize(600,400)# QTableView的最终父类是QWidget  将整个窗口作为一个tab# 创建多个窗口  每个窗口可以放置多个控件# 创建用于显示控件的窗口# 创建窗口tab1self.tab1 = QWidget()# 创建窗口tab2self.tab2 = QWidget()# 创建窗口tab3self.tab3 = QWidget()# 把每个窗口和选项卡绑定self.addTab(self.tab1,'选项卡1')self.addTab(self.tab2,'选项卡2')self.addTab(self.tab3,'选项卡3')# 调用self.tab1UI()self.tab2UI()self.tab3UI()# 为每个选项卡单独编写一个方法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 = TabWidgetDemo()demo.show()sys.exit(app.exec_())

效果展示:

77.堆栈窗口控件(QStakedWidget)

在containers文件夹里面新建QStakedWidget.py文件,执行代码:

"""
堆栈窗口控件(QStackedWidget)通过切换来显示不同页的控件
"""import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *class StackedExample(QWidget):def __init__(self):super(StackedExample, self).__init__()# 从屏幕宽500,高200的位置显示出一个宽300,高200的窗口self.setGeometry(500,200,300,200)self.setWindowTitle("堆栈窗口控件(QStackedWidget)")# 放置列表控件self.list = QListWidget()# 在列表的第一列添加 "联系方式"self.list.insertItem(0,"联系方式")# 在列表的第二列添加  "个人信息"self.list.insertItem(1,"个人信息")# 在列表的第三列添加  "教育程序"self.list.insertItem(2,"教育程度")# 创建三个页面self.stack1 = QWidget()self.stack2 = QWidget()self.stack3 = QWidget()# 调用self.tab1UI()self.tab2UI()self.tab3UI()# 创建堆栈窗口对象self.stack = QStackedWidget()# 把这三个窗口添加到堆栈窗口里面self.stack.addWidget(self.stack1)self.stack.addWidget(self.stack2)self.stack.addWidget(self.stack3)# 创建水平布局 左侧显示列表  右侧显示堆栈页面hbox = QHBoxLayout()hbox.addWidget(self.list)hbox.addWidget(self.stack)# 应用于水平布局self.setLayout(hbox)# 为列表添加事件  当前行变化 信号 槽绑定self.list.currentRowChanged.connect(self.display)# 编写三个槽方法def tab1UI(self):layout = QFormLayout()layout.addRow('姓名',QLineEdit())layout.addRow('地址',QLineEdit())self.stack1.setLayout(layout)def tab2UI(self):layout = QFormLayout()sex = QHBoxLayout()sex.addWidget(QRadioButton('男'))sex.addWidget(QRadioButton('女'))layout.addRow(QLabel('性别'),sex)layout.addRow('生日',QLineEdit())self.stack2.setLayout(layout)def tab3UI(self):layout = QHBoxLayout()layout.addWidget(QLabel('科目'))layout.addWidget(QCheckBox('物理'))layout.addWidget(QCheckBox('高数'))self.stack3.setLayout(layout)def display(self,index):# index 为当前项的变化# 根据索引切换栈里面的页面self.stack.setCurrentIndex(index)if __name__ == '__main__':app = QApplication(sys.argv)main = QStackedWidget()main.show()sys.exit(app.exec_())

效果展示:

windows环境不能展示,待后期填坑

78.停靠控件(QDockWidget)

在containers文件夹里面新建DockWidget.py文件,执行代码:

"""
停靠控件 (QDockWidget)这是一个窗口 可以悬浮 可以拖动
"""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)self.setWindowTitle('停靠控件 (QDockWidget)')# 水平布局layout = QHBoxLayout()# 创建停靠控件self.items = QDockWidget('Dockable',self)# 创建列表控件self.listWidget = QListWidget()# 为列表控件添加itemself.listWidget.addItem('item1')self.listWidget.addItem('item2')self.listWidget.addItem('item3')# 将列表控件放到停靠(控件)窗口里面self.items.setWidget(self.listWidget)# 设置中心窗口self.setCentralWidget(QLineEdit())# 添加停靠窗口  在右侧self.addDockWidget(Qt.RightDockWidgetArea,self.items)# 默认为停靠状态,可以设置为悬浮self.items.setFloating(True)if __name__ == '__main__':app = QApplication(sys.argv)demo = DockDemo()demo.show()sys.exit(app.exec_())

效果展示:

79.容纳多文档的窗口

在containers文件夹里面新建MultiWindows.py文件,执行代码:

"""
容纳多文档的窗口QMdiArea  容纳多文档类
QMdiSubWindow  多文档窗口类# 父窗口可以创建多个子窗口,子窗口不能离开父窗口
"""import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *class MultiWindows(QMainWindow):# 记录一下当前的窗口count = 0def __init__(self,parent=None):super(MultiWindows, self).__init__(parent)self.setWindowTitle("容纳多文档的窗口")# 多文档有两种排列方式 一种是平铺,一种是层叠# 创建容纳多文档对象self.mdi = QMdiArea()# 把多文档对象添加到布局里面self.setCentralWidget(self.mdi)# 创建一个菜单bar = self.menuBar()# 添加一个文件菜单file = bar.addMenu("File")# 给文件菜单添加动作 "New"file.addAction("New")# 设置窗口的排列方式# 层叠file.addAction("cascade")# 平铺file.addAction("Tiled")# 连接菜单动作,触发信号file.triggered.connect(self.windowaction)# 槽方法def windowaction(self,q):print(q.text())# q 是当前单击的菜单项if q.text() == "New":# 记录一下MultiWindows.count = MultiWindows.count + 1# 创建一个子窗口sub = QMdiSubWindow()# 在子窗口里面放置控件sub.setWidget(QTextEdit())# 设置子窗口的标题sub.setWindowTitle('子窗口' + str(MultiWindows.count))# 添加子窗口self.mdi.addSubWindow(sub)# 显示子窗口sub.show()elif q.text() == "cascade":# 设置层叠方式self.mdi.cascadeSubWindows()elif q.text() == "Tiled":# 设置平铺方式self.mdi.tileSubWindows()if __name__ == '__main__':app = QApplication(sys.argv)demo = MultiWindows()demo.show()sys.exit(app.exec_())

效果展示:

80.滚动条控件(QScrollBar)

在containers文件夹里面新建ScrollBar.py文件,执行代码:

"""
滚动条控件(QScrollBar)本身不是容器,但是可以起到容器的作用
QScrollBar的作用:
1.通过滚动条值的变化控制其他控件状态的变化
2.通过滚动条值的变化控制控件位置的变化"""
# 用三个滚动条控件控制文本的颜色变化
# 用一个滚动条控件控制QLableEdit控件的上下移动
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *class ScrollBar(QWidget):def __init__(self):super(ScrollBar, self).__init__()self.initUI()def initUI(self):# 创建水平布局hbox = QHBoxLayout()# 创建label,用来控制文本的颜色以及移动self.label = QLabel('拖动滚动条去改变文字颜色')# 把label添加到水平布局里hbox.addWidget(self.label)# 创建三个滚动条控件# 创建第一个滚动条self.scrollbar1 = QScrollBar()# 设置第一个滚动条的最大值    最小为0self.scrollbar1.setMaximum(255)# 设置信号 滚动条移动  这三个滚动条都使用同一个槽self.scrollbar1.sliderMoved.connect(self.sliderMoved)# 创建第二个滚动条self.scrollbar2 = QScrollBar()# 设置第一个滚动条的最大值    最小为0self.scrollbar2.setMaximum(255)# 设置信号 滚动条移动  这三个滚动条都使用同一个槽self.scrollbar2.sliderMoved.connect(self.sliderMoved)# 创建第三个滚动条self.scrollbar3 = QScrollBar()# 设置第一个滚动条的最大值    最小为0self.scrollbar3.setMaximum(255)# 设置信号 滚动条移动  这三个滚动条都使用同一个槽self.scrollbar3.sliderMoved.connect(self.sliderMoved)# 创建第四个滚动条   用来移动位置self.scrollbar4 = QScrollBar()# 设置第一个滚动条的最大值    最小为0self.scrollbar4.setMaximum(255)# 设置信号 滚动条移动  这三个滚动条都使用同一个槽self.scrollbar4.sliderMoved.connect(self.sliderMoved1)# 把这三个滚动条都添加到水平布局里hbox.addWidget(self.scrollbar1)hbox.addWidget(self.scrollbar2)hbox.addWidget(self.scrollbar3)hbox.addWidget(self.scrollbar4)# 设置当前窗口的位置坐标# 距离屏幕宽300,高300的位置,创建一个宽300高200的窗口self.setGeometry(300,300,300,200)# 应用于水平布局self.setLayout(hbox)# 保留当前的坐标   用来移动位置self.y = self.label.pos().y()# 槽方法def sliderMoved(self):# 打印当前设的值print(self.scrollbar1.value(),self.scrollbar2.value(),self.scrollbar3.value())# 设置调试板palette = QPalette()# 设置颜色c = QColor(self.scrollbar1.value(),self.scrollbar2.value(),self.scrollbar3.value(),255)palette.setColor(QPalette.Foreground,c)self.label.setPalette(palette)# 用button4演示移动def sliderMoved1(self):# x轴坐标不变,用来垂直移动self.label.move(self.label.x(),self.y + self.scrollbar4.value())if __name__ == '__main__':app = QApplication(sys.argv)demo= ScrollBar()demo.show()sys.exit(app.exec_())

效果展示:

81.动态显示当前时间

涉及到PyQt5的多线程

新建multithread文件夹,在multithread文件夹里新建ShowTime.py文件,执行代码:

"""
动态显示当前时间QTimer  定时器  每隔一定时间会调用一次
QThread多线程用于同时完成多个任务    在单CPU上是按顺序完成的(时间片切换),从宏观上来看,还是同时完成的在多CPU上,是可以真正的同时完成
"""import sys
from PyQt5.QtWidgets import QWidget,QPushButton,QApplication,QListWidget,QGridLayout,QLabel
from PyQt5.QtCore import QTimer,QDateTimeclass ShowTime(QWidget):def __init__(self,parent=None):super(ShowTime, self).__init__(parent)# 设置窗口标题self.setWindowTitle("动态显示当前时间")# 创建QLabel控件self.label = QLabel('显示当前时间')# 创建button按扭self.startBtn = QPushButton('开始')# 创建button按钮self.endBtn = QPushButton('结束')# 通过栅格布局,安排这三个控件的位置layout = QGridLayout()# 设置定时器对象self.timer = QTimer()# 时间的 信号 槽self.timer.timeout.connect(self.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):# 开始时间 1sself.timer.start(1000)# 开始之后开始按钮关闭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)demo = ShowTime()demo.show()sys.exit(app.exec_())

效果展示:

82.让程序定时关闭

在multithread文件夹里新建AutoCloseWindow.py文件,执行代码:

"""
让程序定时关闭QTimer.singleShot    在指定时间后只调用一次"""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=140><b>Hello World,窗口在5秒后自动关闭!</b></font>")label.setWindowFlags(Qt.SplashScreen | Qt.FramelessWindowHint)label.show()# 设置五秒QTimer.singleShot(5000,app.quit)sys.exit(app.exec_())

效果展示:

83.使用线程类(QThread)编写计数器

在multithread文件夹里新建Counter.py文件,执行代码:

"""
使用线程类(QThread)编写计数器基本原理
QThread派生一个子类
在这个子类里面定义一个run方法
def run(self):while True:# 每循环一次,休眠一秒钟self.sleep(1)# 当前循环等于5,直接退出if sec == 5:break;QLCDNumber控件WorkThread(QThread)
用到自定义信号
"""import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *# 定义一个变量
sec = 0
class WorkThread(QThread):timer = pyqtSignal()   # 每隔1秒发送一次信号end = pyqtSignal()     # 计数完成后发送一次信号def run(self):while True:self.sleep(1)  # 休眠1秒if sec == 5:self.end.emit() # 发送end信号breakself.timer.emit()  # 发送timer信号class Counter(QWidget):def __init__(self,parent=None):super(Counter, self).__init__(parent)self.setWindowTitle("使用线程类(QThread)编写计数器")self.resize(300,200)# 创建垂直布局layout = QVBoxLayout()self.lcdNumber = QLCDNumber()layout.addWidget(self.lcdNumber)button = QPushButton('开始计数')layout.addWidget(button)# 创建工作线程对象self.workThread = WorkThread()# 绑定 信号 槽self.workThread.timer.connect(self.countTime)self.workThread.end.connect(self.end)# 槽和按钮的单击事件button.clicked.connect(self.work)# 应用于垂直布局self.setLayout(layout)# 槽方法def countTime(self):# global 声明全局变量global secsec += 1self.lcdNumber.display(sec)def end(self):QMessageBox.information(self,'消息','计数结束',QMessageBox.Ok)def work(self):self.workThread.start()if __name__ == '__main__':app = QApplication(sys.argv)demo =Counter()demo.show()sys.exit(app.exec_())

效果展示:

84.用Web浏览器控制(QWebEngineView)显示网页

新建web文件夹,在web文件夹里新建WebEngineView.py文件,执行代码:

"""
用Web浏览器控件(QWebEngineView)显示网页
PyQt5和Web的交互技术同时使用Python和web开发程序,混合开发
Python + JavaScript + HTML5 + CSSQWebEngineView 控件,用来显示Web交互界面"""import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import *class WebEngineView(QMainWindow):def __init__(self):super(WebEngineView, self).__init__()self.setWindowTitle('打开外部网页例子')# 在距屏幕宽5px,高30px的坐标,创建一个宽1355,高730的窗口self.setGeometry(5,30,1355,730)self.browser = QWebEngineView()self.browser.load(QUrl('https://www.baidu.com/'))self.setCentralWidget(self.browser)if __name__ == '__main__':app = QApplication(sys.argv)win = WebEngineView()win.show()sys.exit(app.exec_())

运行过程中,遇到了:No module named ‘PyQt5.QtWebEngineWidgets’

解决办法:

【方法一】 指定安装5.10.1版本的pyqt5

pip install pyqt5==5.10.1

【方法二】 单独安装WebEngine,安装命令为:

pip install PyQtWebEngine

效果展示:

85.装载本地Web页面

在web文件夹新建test.html文件,添加代码如下:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>测试</title>
</head>
<body><h1>Hello PyQt5!</h1><div>晚上好</div><spam>幸苦了</spam>
</body>
</html>

在web文件夹里新建LocalHTML.py文件,执行代码:

"""
装在本地Web页面
"""import sys
import os
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import *class WebEngineView(QMainWindow):def __init__(self):super(WebEngineView, self).__init__()self.setWindowTitle("装载本地Web页面")self.setGeometry(50,50,1355,730)url = os.getcwd() + '/test.html'self.browser =  QWebEngineView()self.browser.load(QUrl.fromLocalFile(url))self.setCentralWidget(self.browser)print(os.getcwd())if __name__ == '__main__':app =    QApplication(sys.argv)demo = WebEngineView()demo.show()sys.exit(app.exec_())

效果展示:

86.显示嵌入Web页面

在new文件里新建InnerHTML.py文件,执行代码:

"""
显示嵌入Web页面
"""import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import *class InnerHTML(QMainWindow):def __init__(self):super(InnerHTML, self).__init__()self.setWindowTitle('显示嵌入Web页面')self.setGeometry(5,30,1355,730)self.browsesr = QWebEngineView()self.browsesr.setHtml("""<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>测试显示</title>
</head>
<body><h1>Hello PyQt5!</h1><div>显示Web页面</div><spam>幸苦了</spam>
</body>
</html>          """)# 设置成中心控件self.setCentralWidget(self.browsesr)if __name__ == '__main__':app =QApplication(sys.argv)demo = InnerHTML()demo.show()sys.exit(app.exec_())

效果展示:

总结:PyQt5支持的三种装载web页面的方式:

1.通过标准的QUrl

2.从本地装载Qurl.fromLocalFile(url)

3.用setHtml直接装载HTML

87.PyQt5调用JavaScript代码

在web文件夹里新建demo1.html文件,添加如下代码:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>测试页面</title><script>function fullname(value) {alert("<" + value + ">")var firstname = document.getElementById('firstname').value;var lastname = document.getElementById('lastname').value;var fullname = firstname + '' + lastname;document.getElementById('fullname').value = fullname;document.getElementById('submit-btn').style.display = "block";return fullname;}</script>
</head>
<form><label>First Name:</label><input type="text" name="firstname" id="firstname"></input><br /><label>First Name:</label><input type="text" name="lastname" id="lastname"></input><br /><label>First Name:</label><input type="text" name="fullname" id="fullname"></input><br /><input style="display: none" type="submit" id="submit-btn" />
</form></body>
</html>

在web文件夹里新建PyQtCallJS.py文件,执行代码:

"""
PyQt5调用JavaScript代码PyQt5和JavaScript交互
PyQt5和JavaScript互相调用,互相传输数据
"""import sys
import os
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import *class PyQtCallJS(QWidget):def __init__(self):super(PyQtCallJS, self).__init__()self.setWindowTitle('PyQt5调用JavaScript')self.setGeometry(5,30,1355,730)# 设置垂直布局self.layout = QVBoxLayout()# 应用于垂直布局self.setLayout(self.layout)# 设置Web页面控件self.browser =  QWebEngineView()url = os.getcwd() + '/demo1.html'self.browser.load(QUrl.fromLocalFile(url))# 把web控件放到布局里self.layout.addWidget(self.browser)button = QPushButton('设置全名')self.layout.addWidget(button)# 槽和信号绑定button.clicked.connect(self.fullname)# 添加按钮的单击事件# 前两个框自己输入,最后一个框自动相加def fullname(self):self.value = 'hello world'self.browser.page().runJavaScript('fullname("' + self.value +'");',self.js_callback)# 通过回调函数返回值def js_callback(self,result):print(result)
if __name__ == '__main__':app = QApplication(sys.argv)demo = PyQtCallJS()demo.show()sys.exit(app.exec_())

效果如下:

88.JavaScript调用PythonAPI计算阶乘

在web文件夹里新建qwebchannel.is文件,添加代码:

/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Klar채lvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtWebChannel module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/"use strict";var QWebChannelMessageTypes = {signal: 1,propertyUpdate: 2,init: 3,idle: 4,debug: 5,invokeMethod: 6,connectToSignal: 7,disconnectFromSignal: 8,setProperty: 9,response: 10,
};var QWebChannel = function(transport, initCallback)
{if (typeof transport !== "object" || typeof transport.send !== "function") {console.error("The QWebChannel expects a transport object with a send function and onmessage callback property." +" Given is: transport: " + typeof(transport) + ", transport.send: " + typeof(transport.send));return;}var channel = this;this.transport = transport;this.send = function(data){if (typeof(data) !== "string") {data = JSON.stringify(data);}channel.transport.send(data);}this.transport.onmessage = function(message){var data = message.data;if (typeof data === "string") {data = JSON.parse(data);}switch (data.type) {case QWebChannelMessageTypes.signal:channel.handleSignal(data);break;case QWebChannelMessageTypes.response:channel.handleResponse(data);break;case QWebChannelMessageTypes.propertyUpdate:channel.handlePropertyUpdate(data);break;default:console.error("invalid message received:", message.data);break;}}this.execCallbacks = {};this.execId = 0;this.exec = function(data, callback){if (!callback) {// if no callback is given, send directlychannel.send(data);return;}if (channel.execId === Number.MAX_VALUE) {// wrapchannel.execId = Number.MIN_VALUE;}if (data.hasOwnProperty("id")) {console.error("Cannot exec message with property id: " + JSON.stringify(data));return;}data.id = channel.execId++;channel.execCallbacks[data.id] = callback;channel.send(data);};this.objects = {};this.handleSignal = function(message){var object = channel.objects[message.object];if (object) {object.signalEmitted(message.signal, message.args);} else {console.warn("Unhandled signal: " + message.object + "::" + message.signal);}}this.handleResponse = function(message){if (!message.hasOwnProperty("id")) {console.error("Invalid response message received: ", JSON.stringify(message));return;}channel.execCallbacks[message.id](message.data);delete channel.execCallbacks[message.id];}this.handlePropertyUpdate = function(message){message.data.forEach(data => {var object = channel.objects[data.object];if (object) {object.propertyUpdate(data.signals, data.properties);} else {console.warn("Unhandled property update: " + data.object + "::" + data.signal);}});channel.exec({type: QWebChannelMessageTypes.idle});}this.debug = function(message){channel.send({type: QWebChannelMessageTypes.debug, data: message});};channel.exec({type: QWebChannelMessageTypes.init}, function(data) {for (const objectName of Object.keys(data)) {new QObject(objectName, data[objectName], channel);}// now unwrap properties, which might reference other registered objectsfor (const objectName of Object.keys(channel.objects)) {channel.objects[objectName].unwrapProperties();}if (initCallback) {initCallback(channel);}channel.exec({type: QWebChannelMessageTypes.idle});});
};function QObject(name, data, webChannel)
{this.__id__ = name;webChannel.objects[name] = this;// List of callbacks that get invoked upon signal emissionthis.__objectSignals__ = {};// Cache of all properties, updated when a notify signal is emittedthis.__propertyCache__ = {};var object = this;// ----------------------------------------------------------------------this.unwrapQObject = function(response){if (response instanceof Array) {// support list of objectsreturn response.map(qobj => object.unwrapQObject(qobj))}if (!(response instanceof Object))return response;if (!response["__QObject*__"] || response.id === undefined) {var jObj = {};for (const propName of Object.keys(response)) {jObj[propName] = object.unwrapQObject(response[propName]);}return jObj;}var objectId = response.id;if (webChannel.objects[objectId])return webChannel.objects[objectId];if (!response.data) {console.error("Cannot unwrap unknown QObject " + objectId + " without data.");return;}var qObject = new QObject( objectId, response.data, webChannel );qObject.destroyed.connect(function() {if (webChannel.objects[objectId] === qObject) {delete webChannel.objects[objectId];// reset the now deleted QObject to an empty {} object// just assigning {} though would not have the desired effect, but the// below also ensures all external references will see the empty map// NOTE: this detour is necessary to workaround QTBUG-40021Object.keys(qObject).forEach(name => delete qObject[name]);}});// here we are already initialized, and thus must directly unwrap the propertiesqObject.unwrapProperties();return qObject;}this.unwrapProperties = function(){for (const propertyIdx of Object.keys(object.__propertyCache__)) {object.__propertyCache__[propertyIdx] = object.unwrapQObject(object.__propertyCache__[propertyIdx]);}}function addSignal(signalData, isPropertyNotifySignal){var signalName = signalData[0];var signalIndex = signalData[1];object[signalName] = {connect: function(callback) {if (typeof(callback) !== "function") {console.error("Bad callback given to connect to signal " + signalName);return;}object.__objectSignals__[signalIndex] = object.__objectSignals__[signalIndex] || [];object.__objectSignals__[signalIndex].push(callback);// only required for "pure" signals, handled separately for properties in propertyUpdateif (isPropertyNotifySignal)return;// also note that we always get notified about the destroyed signalif (signalName === "destroyed" || signalName === "destroyed()" || signalName === "destroyed(QObject*)")return;// and otherwise we only need to be connected only onceif (object.__objectSignals__[signalIndex].length == 1) {webChannel.exec({type: QWebChannelMessageTypes.connectToSignal,object: object.__id__,signal: signalIndex});}},disconnect: function(callback) {if (typeof(callback) !== "function") {console.error("Bad callback given to disconnect from signal " + signalName);return;}object.__objectSignals__[signalIndex] = object.__objectSignals__[signalIndex] || [];var idx = object.__objectSignals__[signalIndex].indexOf(callback);if (idx === -1) {console.error("Cannot find connection of signal " + signalName + " to " + callback.name);return;}object.__objectSignals__[signalIndex].splice(idx, 1);if (!isPropertyNotifySignal && object.__objectSignals__[signalIndex].length === 0) {// only required for "pure" signals, handled separately for properties in propertyUpdatewebChannel.exec({type: QWebChannelMessageTypes.disconnectFromSignal,object: object.__id__,signal: signalIndex});}}};}/*** Invokes all callbacks for the given signalname. Also works for property notify callbacks.*/function invokeSignalCallbacks(signalName, signalArgs){var connections = object.__objectSignals__[signalName];if (connections) {connections.forEach(function(callback) {callback.apply(callback, signalArgs);});}}this.propertyUpdate = function(signals, propertyMap){// update property cachefor (const propertyIndex of Object.keys(propertyMap)) {var propertyValue = propertyMap[propertyIndex];object.__propertyCache__[propertyIndex] = this.unwrapQObject(propertyValue);}for (const signalName of Object.keys(signals)) {// Invoke all callbacks, as signalEmitted() does not. This ensures the// property cache is updated before the callbacks are invoked.invokeSignalCallbacks(signalName, signals[signalName]);}}this.signalEmitted = function(signalName, signalArgs){invokeSignalCallbacks(signalName, this.unwrapQObject(signalArgs));}function addMethod(methodData){var methodName = methodData[0];var methodIdx = methodData[1];// Fully specified methods are invoked by id, others by name for host-side overload resolutionvar invokedMethod = methodName[methodName.length - 1] === ')' ? methodIdx : methodNameobject[methodName] = function() {var args = [];var callback;var errCallback;for (var i = 0; i < arguments.length; ++i) {var argument = arguments[i];if (typeof argument === "function")callback = argument;else if (argument instanceof QObject && webChannel.objects[argument.__id__] !== undefined)args.push({"id": argument.__id__});elseargs.push(argument);}var result;// during test, webChannel.exec synchronously calls the callback// therefore, the promise must be constucted before calling// webChannel.exec to ensure the callback is set upif (!callback && (typeof(Promise) === 'function')) {result = new Promise(function(resolve, reject) {callback = resolve;errCallback = reject;});}webChannel.exec({"type": QWebChannelMessageTypes.invokeMethod,"object": object.__id__,"method": invokedMethod,"args": args}, function(response) {if (response !== undefined) {var result = object.unwrapQObject(response);if (callback) {(callback)(result);}} else if (errCallback) {(errCallback)();}});return result;};}function bindGetterSetter(propertyInfo){var propertyIndex = propertyInfo[0];var propertyName = propertyInfo[1];var notifySignalData = propertyInfo[2];// initialize property cache with current value// NOTE: if this is an object, it is not directly unwrapped as it might// reference other QObject that we do not know yetobject.__propertyCache__[propertyIndex] = propertyInfo[3];if (notifySignalData) {if (notifySignalData[0] === 1) {// signal name is optimized away, reconstruct the actual namenotifySignalData[0] = propertyName + "Changed";}addSignal(notifySignalData, true);}Object.defineProperty(object, propertyName, {configurable: true,get: function () {var propertyValue = object.__propertyCache__[propertyIndex];if (propertyValue === undefined) {// This shouldn't happenconsole.warn("Undefined value in property cache for property \"" + propertyName + "\" in object " + object.__id__);}return propertyValue;},set: function(value) {if (value === undefined) {console.warn("Property setter for " + propertyName + " called with undefined value!");return;}object.__propertyCache__[propertyIndex] = value;var valueToSend = value;if (valueToSend instanceof QObject && webChannel.objects[valueToSend.__id__] !== undefined)valueToSend = { "id": valueToSend.__id__ };webChannel.exec({"type": QWebChannelMessageTypes.setProperty,"object": object.__id__,"property": propertyIndex,"value": valueToSend});}});}// ----------------------------------------------------------------------data.methods.forEach(addMethod);data.properties.forEach(bindGetterSetter);data.signals.forEach(function(signal) { addSignal(signal, false); });Object.assign(object, data.enums);
}//required for use with nodejs
if (typeof module === 'object') {module.exports = {QWebChannel: QWebChannel};
}

在web文件夹里新建h.html文件,添加代码:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>A Demo Page</title><meta charset="UTF-8"><script src="./qwebchannel.js"></script><script language="javascript">function callback(result) {alert("计算结果:" + result)}document.addEventListener("DOMContentLoaded",function () {new QWebChannel( qt.webChannelTransport, function (channel) {window.obj = channel.objects.obj;});});function  onFactorial() {if ( window.obj) {var n = parseInt(document.getElementById('n').value);window.obj.factorial(n,callback)}}</script>
</head>
<body><form><label>请输入N:</label><input type="text" id="n"><br /><input type="button" value="计算阶乘" onclick="onFactorial()"></form>
</body>
</html>

在web文件夹里新建factorical.py文件,添加代码:

"""
用Python语言编写计算阶乘的类
"""
from PyQt5.QtCore import *class Factorial(QObject):@pyqtSlot(int,result=int)def factorial(self,n):if n == 0 or n == 1:return 1else:return self.factorial(n-1)* n

在web文件夹里新建PyFactorial.py文件,执行代码:

"""
JavaScript调用Python函数计算阶乘基本原理
将Python的对象映射到JavaScript中,
通过映射到JavaScript的对象,来调用Python对象的方法或者函数将槽函数映射到JavaScript中在Python类中定义若干个槽函数
系统就会把槽函数连同JavaScript对象一起映射到JavaScript里面调用JS,都是采用异步的方式 加一个回调  window.obj.factorial(n,callback)"""import sys
import osfrom PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWebChannel import QWebChannelfrom PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import *from web.factorial import *channel =QWebChannel()
factorial = Factorial()class PyFactorial(QWidget):def __init__(self):super(PyFactorial, self).__init__()self.setWindowTitle('Python计算阶乘')self.resize(600,300)layout = QVBoxLayout()self.browser = QWebEngineView()url = os.getcwd() + '/h.html'self.browser.load(QUrl.fromLocalFile(url))channel.registerObject("obj",factorial)self.browser.page().setWebChannel(channel)layout.addWidget(self.browser)self.setLayout(layout)if __name__ == '__main__':app = QApplication(sys.argv)demo = PyFactorial()demo.show()sys.exit(app.exec_())

效果展示:

89.绝对布局

新建layout文件夹,在layout文件夹里面新建AbsoluteLayout.py文件,执行代码:

"""
绝对布局
"""import sys,math
from PyQt5.QtWidgets import *class AbsoluteLayout(QWidget):def __init__(self):super(AbsoluteLayout, self).__init__()self.setWindowTitle('绝对布局')self.label1 = QLabel('欢迎',self)self.label1.move(15,20)self.label2 = QLabel('学习',self)self.label2.move(20,40)self.label3 = QLabel('PyQt5',self)self.label3.move(30,80)
if __name__ == '__main__':app = QApplication(sys.argv)demo = AbsoluteLayout()demo.show()sys.exit(app.exec_())

效果展示:

90.水平盒布局

在layout文件夹里面新建HBoxLayout.py文件,执行代码:

"""
水平盒布局(QHBoxLayout)
"""import sys,math
from PyQt5.QtWidgets import *class HBoxLayout(QWidget):def __init__(self):super(HBoxLayout, self).__init__()self.setWindowTitle('水平盒布局')# 创建水平盒布局hlayout = QHBoxLayout()# 往布局里添加按钮控件hlayout.addWidget(QPushButton('按钮1'))hlayout.addWidget(QPushButton('按钮2'))hlayout.addWidget(QPushButton('按钮3'))hlayout.addWidget(QPushButton('按钮4'))hlayout.addWidget(QPushButton('按钮5'))# 此时按钮就会在水平方向等距的排列# 设置控件之间的间距hlayout.setSpacing(40)# 应用水平盒布局self.setLayout(hlayout)if __name__ == '__main__':app = QApplication(sys.argv)demo = HBoxLayout()demo.show()sys.exit(app.exec_())

效果展示:

91.设置控件的对齐方式

在layout文件夹里面新建HBoxLayoutAlign.py文件,执行代码:

"""
设置控件的对齐方式左对齐  右对齐  顶端对齐  底端对齐
"""import sys,math
from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qtclass HBoxLayoutAlign(QWidget):def __init__(self):super(HBoxLayoutAlign, self).__init__()self.setWindowTitle('设置控件的对齐方式')# 创建水平盒布局hlayout = QHBoxLayout()# 往布局里添加按钮控件# 按钮1设置左对齐 顶端对齐hlayout.addWidget(QPushButton('按钮1'),1,Qt.AlignLeft | Qt.AlignTop)hlayout.addWidget(QPushButton('按钮2'),2,Qt.AlignLeft | Qt.AlignTop)hlayout.addWidget(QPushButton('按钮3'))hlayout.addWidget(QPushButton('按钮4'),1,Qt.AlignLeft | Qt.AlignBottom)hlayout.addWidget(QPushButton('按钮5'),1,Qt.AlignLeft | Qt.AlignBottom)# 此时按钮就会在水平方向等距的排列# 设置控件之间的间距hlayout.setSpacing(40)# 应用水平盒布局self.setLayout(hlayout)if __name__ == '__main__':app = QApplication(sys.argv)demo = HBoxLayoutAlign()demo.show()sys.exit(app.exec_())

效果展示:

92.垂直盒布局

在layout文件夹里面新建VBoxLayout.py文件,执行代码:

"""
垂直盒布局(QVBoxLayout)
"""import sys,math
from PyQt5.QtWidgets import *class HVoxLayout(QWidget):def __init__(self):super(HVoxLayout, self).__init__()self.setWindowTitle('垂直盒布局')# 创建水平盒布局hlayout = QVBoxLayout()# 往布局里添加按钮控件hlayout.addWidget(QPushButton('按钮1'))hlayout.addWidget(QPushButton('按钮2'))hlayout.addWidget(QPushButton('按钮3'))hlayout.addWidget(QPushButton('按钮4'))hlayout.addWidget(QPushButton('按钮5'))# 此时按钮就会在水平方向等距的排列# 设置控件之间的间距hlayout.setSpacing(20)# 应用水平盒布局self.setLayout(hlayout)if __name__ == '__main__':app = QApplication(sys.argv)demo = HVoxLayout()demo.show()sys.exit(app.exec_())

效果展示:

92.设置伸缩量(addStretch)

在layout文件夹里面新建Stretch.py文件,执行代码:

"""
设置伸缩量(addStretch)有多种方式,
HBoxLayoutAlign.py中
hlayout.addWidget(QPushButton('按钮1'),1,Qt.AlignLeft | Qt.AlignTop) 中的第二个参数 1 就是伸缩量
"""import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *class Stretch(QWidget):def __init__(self):super(Stretch, self).__init__()self.setWindowTitle("设置伸缩量")self.resize(800,400)# 添加三个按钮btn1 = QPushButton(self)btn2 = QPushButton(self)btn3 = QPushButton(self)btn4 = QPushButton(self)btn5 = QPushButton(self)# 分别设置文本btn1.setText('按钮1')btn2.setText('按钮2')btn3.setText('按钮3')btn4.setText('按钮4')btn5.setText('按钮5')# 放置水平布局layout = QHBoxLayout()# 把三个按钮添加到布局里layout.addStretch(0)layout.addWidget(btn1)layout.addWidget(btn2)layout.addWidget(btn3)layout.addWidget(btn4)layout.addWidget(btn5)btnOK = QPushButton(self)btnOK.setText("确定")layout.addStretch(1)layout.addWidget(btnOK)btnCancel = QPushButton(self)btnCancel.setText("取消")layout.addStretch(2)layout.addWidget(btnCancel)# 应用于水平布局self.setLayout(layout)if __name__ == '__main__':app = QApplication(sys.argv)demo = Stretch()demo.show()sys.exit(app.exec_())

效果展示:

93.让按钮永远在窗口的右下角

在layout文件夹里面新建RightBottomButton.py文件,执行代码:

"""
让按钮永远在窗口右下角基本原理:
一分为二界面
上面任意布局
按钮放在水平布局里面
"""import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *class RightBottomButton(QWidget):def __init__(self):super(RightBottomButton, self).__init__()self.setWindowTitle('让按钮永远在右下角')self.resize(400,300)# 添加两个按钮okButton = QPushButton("确定")cancelButton = QPushButton("取消")# 设置水平盒布局hbox = QHBoxLayout()hbox.addStretch(1)hbox.addWidget(okButton)hbox.addWidget(cancelButton)# 设置垂直盒布局vbox = QVBoxLayout()btn1 = QPushButton('按钮1')btn2 = QPushButton('按钮2')btn3 = QPushButton('按钮3')btn4 =  QPushButton('按钮4')btn5 = QPushButton('按钮5')vbox.addStrut(0)vbox.addWidget(btn1)vbox.addWidget(btn2)vbox.addWidget(btn3)vbox.addWidget(btn4)vbox.addWidget(btn5)# 把水平盒布局添加到垂直盒布局里vbox.addStrut(2)vbox.addLayout(hbox)# 应用于垂直盒布局self.setLayout(vbox)if __name__ == '__main__':app = QApplication(sys.argv)demo = RightBottomButton()demo.show()sys.exit(app.exec_())

效果展示:

未完待续…

PyQt5保姆级教程-- 从入门到精通相关推荐

  1. B站python教程“清华大佬终于把Python讲的如此清新脱俗!保姆级教程从入门到精通”视频学习笔记p1-p85

    1.python脚本的格式:hello.py 其中hello为脚本名,py为脚本格式,在终端可以用python hello.py进行脚本的执行 2.什么是头注释:不是为代码而服务,更多是被系统或解释器 ...

  2. un系统服务器双网卡,「保姆级教程」unRaid入门到精通七:直通网卡、硬盘和其它PCI硬件设备...

    本章前言: 上一章节讲过unRaid安装NVIDIA驱动独立显卡加速EMBY,详细见<「保姆级教程」unRaid入门到精通六:unRaid安装NVIDIA驱动独立显卡加速EMBY>,本章将 ...

  3. Unified Functional Testing(UFT)15.0.2入门保姆级教程(二),图文详解。QTP

    UFT入门之验证点和参数化 UFT15.0.2教程之侦测器(ObjectSpy)及脚本录制 请移步:Unified Functional Testing(UFT)15.0.2入门保姆级教程(一),图文 ...

  4. Unified Functional Testing(UFT)15.0.2入门保姆级教程(一),图文详解。QTP

    UFT入门之侦测器(ObjectSpy)及录制第一个脚本 实验说明 1.Quick Test Pro(QTP)11.5后更名为Unified Functional Testing(UFT) 2. 实验 ...

  5. XML快速入门的保姆级教程!!!

    XML快速入门的保姆级教程!!! 简介 基础语法 组成部分 约束 约束分类 DTD schema 解析 Jsoup Jsoup:工具类,可以解析html或xml文档,返回Document对象 Docu ...

  6. ROS入门保姆级教程:5-ROS计算图

    ROS入门往期: ROS入门保姆级教程:1-hello world初体验 ROS入门保姆级教程:2-VScode中使用ROS ROS入门保姆级教程:3-ROS文件系统 ROS入门保姆级教程:4-ROS ...

  7. Shopify开发入门-保姆级教程

    Shopify开发入门-保姆级教程

  8. 前端涨薪必读,node.js入门保姆级教程

    Node.js保姆级教程 1. Node基本概念 2. 第一个node.js程序 3. node创建get请求 4. node创建post请求 1. Node基本概念 1.1 node.js是什么? ...

  9. 女友问粉丝过万如何庆祝,我发万字长文《保姆级大数据入门篇》感恩粉丝们支持,学姐|学妹|学弟|小白看了就懂

    2021大数据领域优质创作博客,带你从入门到精通,该博客每天更新,逐渐完善大数据各个知识体系的文章,帮助大家更高效学习. 有对大数据感兴趣的可以关注微信公众号:三帮大数据 目录 粉丝破万了 新星计划申 ...

  10. 【Midjourney实操】逼真到颤抖!保姆级教程教生成效果炸裂的图片

    最近,许多由Midjourney V5创作的画作在网络上引起了热议,许多人惊呼:人类画师, 插画师, 设计师统统活不下去了! 比如下面这张中国情侣的画作: 因为前段时间这个很火, 我跟着同样的prom ...

最新文章

  1. [盘点]从《行者无疆》开始了解欧洲
  2. python脚本编写_如何用Python包编写一个简单的脚本,表达你对父母的爱?
  3. python程序设计实验报告实验程序流程序列化_Python使用pickle模块实现序列化功能示例...
  4. 通过IP地址查计算机名
  5. 图形工具包 linux,GTK 4.0图形工具包正式发布:时隔四年的重大版本!
  6. visio中公式太小_visio绘图中的数据计算
  7. Python+django网页设计入门(9):自定义反爬虫功能
  8. 如何格式化电脑_电脑硬盘不小心格式化如何恢复【恢复方法】
  9. 对“才鸟”——动态显示扩展数据的改写
  10. python中format函数怎么样提取字符串里的字符_Python中用format函数格式化字符串的用法...
  11. 计算机说课稿模板小学数学,小学数学说课万能模板精简
  12. 设计模式(一)——统一建模语言基础知识
  13. QQ登录界面测试用例设计:
  14. uview框架u-form表单校验,rules校验对象中对象的值(解决 当form属性嵌套对象时未取到值的问题)
  15. 一个Web前端实习生的简历
  16. 温哥华岛大学计算机科学,温哥华有哪些知名大学排名(温哥华地区大学排名一览)...
  17. 同一wifi下电脑共享文件夹
  18. 部落卫队问题 (回溯)
  19. 5分钟搭建大数据学习环境
  20. 商业级、工业级、军品级、宇航级CPU有着不同标准

热门文章

  1. G502使用计算机配置,罗技G502鼠标灵敏度如何设置?宏如何设置?
  2. win10下如何安装.NetFrame3.5框架
  3. 【MFC开发(5)】单选按钮控件RADIOBUTTON
  4. 计算机组成原理第三章ppt,计算机组成原理第三章幻灯片(白中英版).ppt
  5. Fortran程序转换到c程序
  6. mysql 个版本区别_MySQL版本区别及选择
  7. Java性能调优面试题及答案(性能优化面试题)
  8. 1.c语言的基本框架,C语言基本程序框架
  9. java jbpm工作流_[JAVA] Jbpm工作流引擎原理及Jbpm复杂流程实现视频课程
  10. 计算机网络安全基础知识