行业知识
PyQt5保姆级教程-- 从入门到精通
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-toolsERROR: 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 ...加入--user为pip 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,高度150 w.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.translate MainWindow.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 sysimport 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.translate MainWindow.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 sysimport 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 sysimport 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 sysimport 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 sysimport 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 sysimport 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() # 在状态栏上,设置消息的状态时间5000ms self.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() # 获取屏幕的宽度、高度 # 窗口左边缘的坐标等于(屏幕的宽度-窗口的宽度)/2 newLeft = (screen.width()-size.width()) / 2 # 屏幕上边缘的坐标等于(屏幕的高度-窗口的高度) / 2 newTop = (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,引入了QPushButtonimport sysfrom 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.button1 self.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 sysfrom PyQt5.QtWidgets import QHBoxLayout,QMainWindow,QApplication,QPushButton,QWidget# 创建实例app = QApplication(sys.argv)# 创建窗口widget = QWidget()# 在窗口里放buttonbtn = 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 sysfrom 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('今天是个好日子') # 设置窗口的位置和尺寸 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 sysfrom 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('今天是个好日子') # 设置窗口的位置和尺寸 self.setGeometry(300,300,200,200) # 设置窗口的标题 self.setWindowTitle('设置控件提示消息') # 添加butoon按钮并设置提示信息 # 添加Button # 创建全局对象self.button1 self.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背景色# 导入显示图片包QPixmapfrom 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("这是一个文本标签.") # 用调试板自动填充背景 label1.setAutoFillBackground(True) # 创建调试板 palette = QPalette() # 给调试板设置背景色 palette.setColor(QPalette.Window,Qt.blue) # 对label1使用调试板 label1.setPalette(palette) # 让label1居中对齐 label1.setAlignment(Qt.AlignCenter) # 给label2设置标签 label2.setText("欢迎使用Python GUI程序") # 可以在a标签里触发事件或者跳转网页 二者选其一 # 给label3设置文本居中 label3.setAlignment(Qt.AlignCenter) # 给label3设置提示文本 label3.setToolTip('这是一个图片标签') # 让label3显示图片 label3.setPixmap(QPixmap("./images/4.jpg")) # 同级目录写法./images # 给label4设置文本内容 label4.setText("打开百度") # setText里面的内容要用双引号,单引号会报错 # 让label4打开链接 # 如果设为True,用浏览器打开网页,如果设为False,调用槽函数 label4.setOpenExternalLinks(True) # 让label4的文本右对齐 label4.setAlignment(Qt.AlignRight) # 给label4设置提示文本 label4.setToolTip('这是一个超链接') # 创建一个垂直布局 vbox = QVBoxLayout() # 分别把这四个控件放到这个布局里面 布局函数 addWidget vbox.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 sysfrom 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,一个上面写Cancel btnOK = 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 sysfrom 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 sysfrom PyQt5.QtWidgets import *# 导入PyQt5的正则(三个校验器,第三个可自定义)from PyQt5.QtGui import QIntValidator,QDoubleValidator,QRegExpValidator# 导入PyQt5里正则表达式的一个类QRegExpfrom 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) |
| > | 所有的字母字符都大写 |
| 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) # 搜索满足条件的Cell text = '(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 sysfrom 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 sysfrom 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.AscendigOrder else: # 如果是升序,改成降序 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 sysfrom 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 sysfrom 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, QFontfrom 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)) #改变行的高度 第一个参数是行 第二个参数是设定值 第一行 高度80 tableWidget.setRowHeight(0,120) # 把字段添加到表格里 第一行第二列 tableWidget.setItem(0, 1, newItem) # 创建字段 newItem = QTableWidgetItem('167') # 设置字体 字体大小 newItem.setFont(QFont('Times', 60, QFont.Black)) # 改变第三行的高度 第三行 高度80 tableWidget.setRowHeight(2,20) # 改变列的高度 第一个参数是列 第二个参数是设定值 第三列 宽度120 tableWidget.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 sysfrom 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 sysfrom 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 Qtfrom 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 |
上一篇:发帖为什么要审核?