目录
什么是pyQT
为什么要开发桌面应用
要讲些什么
搭建PyQt5开发环境
参见CSDN:pyQt5环境的搭建_Hi~晴天大圣的博客-CSDN博客_pyqt5环境搭建
1 Python
2 PyQt模块插件
PyQt5中插件的作用: QtDesigner——通过Qt语言进行UI设计(支持拖拽式的UI设计) PyUIC——主要用来将QtDesigner代码转化成Python代码 Pyrcc—— 将图片、数据文件资源打包成py文件
3 PyCharm
添加到环境变量:环境变量目录
问题:在安装第三方库时出现报错"These Packages Do Not Match The Hashes From The Requirements File."
python在虚拟解释器环境中使用pip安装第三方库出现Requirement already satisfied错误
1到14课时后续学习后添加!
课时15 开发第一个基于PyQt5的桌面应用
课时16 打开QtDesigner设计师工具
ctrl+R预览
将.ui文件转换为.py文件
方法一: python -m PyQt5.uic.pyuic demo.ui -o demo.py
方法二:
python文件夹//打开pyuic5程序 -o 文件名称 直接生成demo.py
推荐 方式三
课时17 在QtDesigner中使用布局
课时18 调用源文件:RunDemo.py调用demo.py文件
课时19 PyQt5中的浏览器控件-QtWebEngine
课时20 Edit 编辑伙伴 编辑Tab顺序
课时21 在Qt Designer中设置信号与插槽
课时22 动作编辑器
课时23 主窗口类型
QMainWindow:可以包含菜单栏,工具栏,状态栏和标题栏
QDialog:是对话窗口的基类。没有菜单栏,工具栏,状态栏
QWidget:不确定窗口的用途,就使用QWidget
课时24 接下来用代码写一个程序Demo
课时25 让程序居中窗口
课时26 退出应用程序
课时27 获取屏幕坐标系
课时28 设置窗口和应用程序图标
课时29 显示控件提示信息
课时30 QLabel控件的基本用法
课时31 QLabel与伙伴关系
课时32 QLineEdit控件与回显模式
课时33 限制QLineEdi t控件的输入
校验器
课时34 使用掩码限制QLineEdit控件的输入
课时35 QLineEdit综合案例
课时36 使用QTextEdit控件输入多行文本
课时37 按钮控件(QpushButton)
单选按钮控件QRatioButton
课时39 复选框控件QCheckBox编辑编辑
课时40 下拉列表控件QComboBox
课时41 滑块控件QSlider
课时42 计数器控件QSpinBox
课时43 使用 QDialog显示通用对话框
课时44 显示不同类型的消息对话框
课时45 输入对话框QInputDialog
课时46 字体对话框QFontDialog
课时47 颜色对话框QColorDialog
课时48 文件对话框QFileDialog
课时49 在窗口上绘制文本
课时50 用像素点绘制正弦曲线
编辑
课时51 绘制不同类型的直线
课时52 绘制各种图形
课时53 用画刷填充图形区域
课时54 让控件支持拖拽动作
课时55 使用剪贴板
课时56 日历控件
课时57 设置不同风格的日期和时间
课时58 日期和时间控件的高级操作
课时59 创建和使用菜单
课时60 创建和使用工具栏
课时61 创建和使用状态栏
用于显示状态信息,一般在窗口的最下方显示
课时62 使用打印机
课时63 显示打印对话框
课时64 显示二维表数据
课时65 显示列数据
课时66 扩展的列表控件
课时67 扩展的表格控件
课时68 在单元格中放置控件
课时69 在表格中搜索Cell和行定位
课时70 设置单元格字体和颜色
课时71 按表格的某一列排序
课时71 设置单元格的文本对齐方式
课时73 合并单元格
课时74 设置单元格的尺寸
课时75 在单元格中实现图文混排的效果
课时76 改变单元格中图片的尺寸
课时77 在表格中显示上下文菜单
课时78 树控件(QTreeWidget)的基本用法
编辑
课时79 为树节点添加响应事件
课时 80 增加,修改和删除树控件的节点
课时81 QTreeView控件与系统定制模式
课时82 选项卡控件(QTabWidget)
课时83 堆栈窗口控件(QStackedWidget)
课时84 停靠控件(QDockWidget)
课时85 容纳多文档的窗口
课时86 滚动条控件(QScrollBar)
课时87 动态显示当前时间(QTimer)
课时88 让窗口定时关闭
课时89 使用线程类(QThread)编写计数器
课时90 用Web浏览器控件(QWebEngineView)显示网页
课时91 装载本地Web页面
课时91 显示嵌入Web页面
课时93 PyQt5调用JavaScript代码,并返回值
课时94 JavaScript调用PyhtonAPI计算阶乘
课时95 绝对布局
课时96 水平盒布局(QHBoxLayout)
课时97 设置控件的对齐方式
课时98 垂直盒布局
课时99 设置布局的伸缩量
课时100 让按钮永远在窗口的右下角
课时101 栅格布局:用循环方式实现计算器UI
课时102 栅格布局:进行表单UI设计
课时103 表单布局
课时104 拖动控件之间的边界(QSplitter)
课时105 信号与槽基础
课时106 自定义信号实现对象之间的通信
课时107 可以传递多个参数的信号
课时108 为类添加多个信号(重载形式的信号)
课时109 信号与槽的N对N连接与断开连接
课时110 为窗口添加信号
课时111 多线程更新UI数据
课时112 信号与槽自动连接
课时113 用Lambda表达式为槽函数传递参数
课时114 用partial对象为槽函数传递参数
课时115 override(覆盖)槽函数
课时116 多窗口交互(1):不使用信号与槽
课时117 多窗口交互(2):使用信号与槽
课时118 设置窗口中控件的风格
课时119 设置窗口样式
课时120 用代码设置窗口的最大化和最小化
课时121 项目实战:实现绘图应用
课时122 QSS基础
课时123 使用QSS选择器设置控件样式
课时124 QSS子控件选择器
课时125 使用QSS为标签和按钮添加背景图
课时126 装载QSS文件
课时127 三种设置背景色和背景图片的方式
方式一 QSS
方式二 QPalette
方式三 直接绘制
课时127 实现不规则窗口(异形窗口)注意只对windowse系统有效果
课时128 移动和关闭不规则窗口(异形窗口)
课时129 实现异形窗口动画效果编辑
课时130 装载gif动画文件
课时131 缩放图片
课时132 用动画效果改变窗口的尺寸
课时133用动画效果以不同速度移动窗口
课时134 用PyInstaller打包PyQt5应用
课时135 操作SQLite数据库
课时136 使用可视化的方式对SQLite数据库进行增删改查操作
课时137 分页显示数据
课时138 使用PyQtGraph进行数据可视化
pyqt是一个用于创建GUI应用程序的跨平台工具包,它将python与qt库融为一体。也就是说,pyqt允许使用python语言调用qt库中的API。这样做的最大好处就是在保存了qt高运行效率的同时,大大提高开发效率。因为,使用python语言开发程序要比使用c++语言开发程序快的多。pyqt对qt做了完整的封装,几乎可以用pyqt做qt能做的任何事情。
由于目前最新的pyqt版本是5.11,所以习惯上称呼为pyqt为pyqt5
桌面应用,也可以成为GUI应用,在windows处于非常火爆的15年时间(1995到2010)里是非常火的,不过最近几年web应用和移动应用抢了风头。尽管web和移动应用看似成为现在的主流。但桌面应用目前仍然为很多类型应用的首选。移动应用由于屏幕太小,机器性能远低于同时代的pc机,所以至少目前来看,在短时间内移动应用是无法取代pc应用的,而在pc浏览器上运行的web应用的主要优势是不需要安装的,只要有浏览器就可以运行。
但缺点也显而易见,web应用在浏览器部分的逻辑代码通常都是由于javascript语言编写的,运行效率比较低,而且web应用是无法完全控制本机的硬件的,如摄像头,蓝牙设备,打印机,串口等,web应用在用户体验上也不如同时代的桌面应用,而web设备不擅长的事正好是桌面应用的强项,因此,在未来的几十年,桌面应用仍然会占有非常重要的地位。
Qt Designer
pyQt5基本窗口控件(QMainWindow,Qwidget,Qlabel,QLineEdit,菜单,工具栏等)
pyQt5高级控件(QTableView,QListView,容器,多线程等)
pyQt5布局管理(QBoxLayout,QGridLayout,QFormLayout,嵌套布局等)
pyQt5信号与槽(事件处理,数据传递等)
pyQt5图形与特效(定制窗口风格,绘图,QSS与UI美化,不规则窗口,设置样式等)
pyQt5扩展应用(制作pyQt5安装程序,数据处理,第三方绘图库在pyQt5中的应用,UI自动化测试等)
参见CSDN:pyQt5环境的搭建_Hi~晴天大圣的博客-CSDN博客_pyqt5环境搭建
1 Python
2 PyQt模块插件
PyQt5中插件的作用:
QtDesigner——通过Qt语言进行UI设计(支持拖拽式的UI设计)
PyUIC——主要用来将QtDesigner代码转化成Python代码
Pyrcc—— 将图片、数据文件资源打包成py文件3 PyCharm
因为这里存在网络慢的原因 我使用了手机数据分享给电脑的方式下载的PyQt5
添加到环境变量:环境变量目录
C:\Users\xiangbin\AppData\Local\Programs\Python\Python39\Lib\site-packages\PyQt5\Qt5\plugins
问题:在安装第三方库时出现报错"These Packages Do Not Match The Hashes From The Requirements File."
原因:通常是因为网速问题导致的下载错误,导致对应的哈希值不匹配。
解决方法:需要在pip时,添加"–upgrade"参数即可。通常这时下载还会报错timeout,因此多加一个"–default-timeout=100000" 更为保险(timeout的赋值可以视情况变化)。
pip install --upgrade --default-timeout=100000 packagename -i http://pypi.douban.com/simple
当使用conda安装完pyqt5后,在pycharm中配置额外模块时发现找不到designer.exe文件
经过查资料发现,是因为我安装pyqt5时,里面不带这个pyqt5-tools文件,所以在使用conda下的pip下载pyqt5-tools即可(conda是下载不了pyqt5-tools的)
解决方法,在命令行中输入pip install PyQt5-tools -i http://pypi.douban.com/simple --trusted-host=pypi.douban.com即可python在虚拟解释器环境中使用pip安装第三方库出现Requirement already satisfied错误
原因是:用项目自己创建的虚拟解释器环境时,因为没有配置系统环境变量,所以找不到要安装的地址,不知道这个包要安装到那个位置。
解决办法,在安装语句中加- -target,指定安装的位置,用项目虚拟解释器环境安装的话,安装位置为项目中的虚拟环境中,默认为:pip install --target=项目路径\项目名称\venv\Lib\site-packages 要安装的包名
例如:
pip install --target=C:\Users\xiangbin\AppData\Local\Programs\Python\Python39\Lib\site-packages PyQt5-tools
开发环境前期准备工作搭建完成!
课程讲解开始
课时1 请自考笔者第二篇文章http://t.csdn.cn/3EiEX
课时2请自考笔者第二篇文章http://t.csdn.cn/3EiEX
课时3 请自考笔者第二篇文章http://t.csdn.cn/3EiEX
课时4 请自考笔者第二篇文章http://t.csdn.cn/3EiEX
课时5请自考笔者第二篇文章http://t.csdn.cn/3EiEX
课时6 请自考笔者第二篇文章http://t.csdn.cn/3EiEX
课时7 请自考笔者第二篇文章http://t.csdn.cn/3EiEX
课时8 请自考笔者第二篇文章http://t.csdn.cn/3EiEX
课时9 请自考笔者第二篇文章http://t.csdn.cn/3EiEX
课时10 请自考笔者第二篇文章http://t.csdn.cn/3EiEX
课时11 请自考笔者第二篇文章http://t.csdn.cn/3EiEX
课时12 请自考笔者第二篇文章http://t.csdn.cn/3EiEX
课时13 请自考笔者第二篇文章http://t.csdn.cn/3EiEX
课时14 请自考笔者第二篇文章http://t.csdn.cn/3EiEX
课时15 开发第一个基于PyQt5的桌面应用
# @CSDN王家视频教程图书馆
# @Time 2022/11/22 17:59
import sys
from PyQt5.QtWidgets import QApplication,QWidget
'''
鉴于这两种情况中__name__的值是不同的:当一个模块被直接执行时,其__name__必然等于__main__;当一个模块被引用时,
其__name__必然等于文件名(不含.py)。所以利用判断__name__ == '__main__'的真假就可以将这两种情况区分出来。
'''
if __name__ == '__main__':
#创建QApplication类的实例
app=QApplication(sys.argv)
#创建一个窗口
w = QWidget()
#设置窗口的尺寸
w.resize(300,150)
#移动窗口
w.move(300,300)
#设置窗口的标题
w.setWindowTitle('第一个基于pyqt的桌面程序')
#显示窗口
w.show()
#进入程序的主循环 并通过exit函数确保主循环安全结束
sys.exit(app.exec_())
或者
ctrl+R预览
生成完成 !demo.py
python文件夹//打开pyuic5程序 -o 文件名称 直接生成demo.py
生成完成 !demo1.py
全选控件 右键 选择布局 为水平布局
其他布局设置方式同理 因为第二扩展菜单截图 截不到 这里请参考
CTRL + R 预览
新版本的QtDesigner里是没有WebView的,想要使用浏览器控件就需要自己安装QtWebEngine。安装之后也是没有图形界面的控件的,所以使用策略就是
用其他控件在图形界面布局,然后生成python代码之后在代码中修改
修改代码参考如下
from PyQt5 import QtWebEngineWidgets
self.webView = QtWebEngineWidgets.QWebEngineView(self.centralwidget)
self.webView.setGeometry(QtCore.QRect(300, 300, 451, 241))
self.webView.setUrl(QtCore.QUrl("https://markwannafly.blog.csdn.net/"))
self.webView.setObjectName("webView")或者:如何在Python QT Designer中插入Web浏览器
信号(signal)
是Qt的核心机制,也是PyQt的核心机制
信号:是由对象或者控件发射出去的消息
按钮的单击事件
当单击按钮时,按钮就会向外部发送单击消息,这些发送出去的信号需要一些代码来拦截,这些代码就是插槽上一个函数或者方法
一个信号可以和多个槽绑定,一个槽可以拦截多个信号
有3种窗口
QMainWindow
QWidget
QDialog
QDialog:是对话窗口的基类。没有菜单栏,工具栏,状态栏
QWidget:不确定窗口的用途,就使用QWidget
这里分享一个在线icon制作的网站:Icon图标在线制作工具
# @CSDN王家视频教程图书馆
# @Time 2022/11/22 23:14
import sys
from PyQt5.QtWidgets import QMainWindow,QApplication
from PyQt5.QtGui import QIcon
class FirstMainWin(QMainWindow):
def __init__(self):
super(FirstMainWin,self).__init__()
#设置主窗口的标题
self.setWindowTitle("第一个主窗口应用")
#设置窗口的尺寸
self.resize(400,300)
self.status=self.statusBar()
self.status.showMessage("只存在5秒的消息",5000)
#只有本程序可以调用 防止其他程序调用本程序
if __name__ == '__main__':
app=QApplication(sys.argv)
app.setWindowIcon(QIcon('./and.png'))
main=FirstMainWin()
main.show()
# 程序的主循环
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 11:38
# 龙文学python
# @Time 2022/11/22 23:14
import sys
from PyQt5.QtWidgets import QDesktopWidget,QMainWindow,QApplication
from PyQt5.QtGui import QIcon
class CenterForm(QMainWindow):
def __init__(self):
super(CenterForm,self).__init__()
#设置主窗口的标题
self.setWindowTitle("让主窗口居中")
#设置窗口的尺寸
self.resize(400,300)
def center(self):
# 获取屏幕坐标系
screen=QDesktopWidget.screenGeometry()
#获取窗口坐标系
size=self.geometry()
newLeft=(screen.width()-size.width())/2
newTop=(screen.height()-size.height())/2
self.move(newLeft,newTop)
#只有本程序可以调用 防止其他程序调用本程序
if __name__ == '__main__':
app=QApplication(sys.argv)
app.setWindowIcon(QIcon('./and.png'))
main=CenterForm()
main.show()
# 程序的主循环
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 12:11
import sys
from PyQt5.QtWidgets import QDesktopWidget,QHBoxLayout,QMainWindow,QApplication,QPushButton,QWidget
def onClick_Button():
print("第一种方式 窗口坐标系 包含标题栏")
print("widget.x()=%d" % widget.x())
print("widget.y()=%d" % widget.y())
print("widget.width()=%d" % widget.width())
print("widget.height()=%d" % widget.height())
print("第二种方式 窗口坐标系 不包含标题栏 只有工作区")
print("widget.geometry().x()=%d" % widget.geometry().x())
print("widget.geometry().y()=%d" % widget.geometry().y())
print("widget.geometry().width()=%d" % widget.geometry().width())
print("widget.geometry().height()=%d" % widget.geometry().height())
print("第三种方式 暂时未理解全面")
print("widget.frameGeometry().x()=%d" % widget.frameGeometry().x())
print("widget.frameGeometry().y()=%d" % widget.frameGeometry().y())
print("widget.frameGeometry().width()=%d" % widget.frameGeometry().width())
print("widget.frameGeometry().height()=%d" % widget.frameGeometry().height())
app=QApplication(sys.argv)
widget=QWidget()
btn=QPushButton(widget)
btn.setText('按钮')
btn.clicked.connect(onClick_Button)
btn.move(55,55)
widget.resize(300,240)#设置工作区的尺寸
widget.move(250,200)
widget.setWindowTitle('屏幕坐标系')
widget.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 12:40
'''
窗口的setWindowIcon方法用于设置窗口的图标,只在windows中可用
QAplication中的setQindowIcon的方法用于设置主窗口的图标和应用程序图标,但调用了窗口的setWindowIcon方法
QAplication中的setQindowIcon的方法就只能用于设置应用程序图标了
'''
import sys
from PyQt5.QtWidgets import QDesktopWidget,QMainWindow,QApplication
from PyQt5.QtGui import QIcon
class IconFrom(QMainWindow):
def __init__(self):
super(IconFrom,self).__init__()
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 250, 250)
#设置主窗口的标题
self.setWindowTitle("设置窗口图标")
#设置窗口图标
self.setWindowIcon(QIcon('./and.png'))
#只有本程序可以调用 防止其他程序调用本程序
if __name__ == '__main__':
app=QApplication(sys.argv)
#app.setWindowIcon(QIcon('./and.png'))
main=IconFrom()
main.show()
# 程序的主循环
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 12:51
#显示控件提示信息
import sys
from PyQt5.QtWidgets import QDesktopWidget,QHBoxLayout,QMainWindow,QApplication,QToolTip,QPushButton,QWidget
from PyQt5.QtGui import QIcon
from PyQt5.QtGui import QFont
class TooltipForm(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
QToolTip.setFont(QFont("SansSerif",12))
self.setToolTip('今天是星期五')
self.setGeometry(300,300,200,200)
self.setWindowTitle('设置控件提示信息')
# 添加Button
self.button1 = QPushButton("我的按钮")
self.button1.setToolTip('这是一个按钮ok')
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=QApplication(sys.argv)
app.setWindowIcon(QIcon('./and.png'))
main=TooltipForm()
main.show()
# 程序的主循环
sys.exit(app.exec_())
QLabel控件
setAlignment():设置文本的对齐方式
setIndent():设置文本缩进
text():获取文本内容
selectedText():返回所选择的字符
setWordWrap():设置是否允许换行
QLabel常用的信号(事件):
1.当鼠标滑过QLabel控件时出发:linkHovered
2.当鼠标单击QLabel控件时触发:linkActivated
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 12:51
import sys
from PyQt5.QtWidgets import QApplication, QLabel, QWidget, QVBoxLayout # 垂直布局
from PyQt5.QtGui import QPalette # 调色版
from PyQt5.QtGui import QPixmap # 展示图片
from PyQt5.QtCore import Qt # 有一些常量在这里面,eg:blue
class QLabelDdemo(QWidget):
def __init__(self):
super(QLabelDdemo, self).__init__()
self.initUI()
def initUI(self):
label1 = QLabel(self)
label2 = QLabel(self)
label3 = QLabel(self)
label4 = QLabel(self)
label1.setText('这是一个文本标签')
label1.setAutoFillBackground(True) # 自动填充背景
palette = QPalette()
# 设置背景色
palette.setColor(QPalette.Window, Qt.blue)#设置背景色
# 对label1设置调色版
label1.setPalette(palette)
# 跳转到一个网页或者触发一个点击事件
label2.setText("欢迎使用Python GUI程序")
# 文本居中
label3.setAlignment(Qt.AlignCenter)
# 提示信息
label3.setToolTip('这是一个图片标签')
label3.setPixmap(QPixmap('./and.png'))
# 如果设为True,用浏览器打开网页,如果设为False,调用槽函数
label4.setOpenExternalLinks(True)
label4.setText("打开百度")
# 右对齐
label4.setAlignment(Qt.AlignRight)
label4.setToolTip('这是一个超级链接')
vbox = QVBoxLayout()
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控件演示')
self.resize(400, 300)
return
def linkHovered(self):
print('当鼠标滑过label2标签时,触发事件')
def linkClicked(self):
print('当鼠标单击label4标签时,触发事件')
if __name__ == '__main__':
app = QApplication(sys.argv)
main = QLabelDdemo()
main.show()
sys.exit(app.exec_())
伙伴关系
举例:栅格布局下给控件设置伙伴关系
addWidget函数:
mainLayout . addWidget(控件对象, rowIndex, columnIndex, row, column)
第一个参数是要添加的控件对象,第二个和第三个是位置索引(行,列),就像矩阵一样是从(0,0)开始的,第四,五参数是空间大小,第四个是占几行,第五个是占几列
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 14:12
from PyQt5.QtWidgets import *
import sys
'''
QLabel与伙伴控件
控件对象 #组件对象
rowIndex,columnIndex #控件位置
row,column #指定控件的尺寸
mainLayout.addWidget(控件对象,rowIndex,columnIndex,row,column)
'''
class QLabelBuddy(QDialog):
def __init__(self):
super(QLabelBuddy, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('QLabel与伙伴关系')
self.resize(400, 150)
# &代表设置热键,其后第一个字母就是热键,不区分大小写,Alt+热键调用即可
nameLabel = QLabel('&Name(N)', self) # designer下的label
nameLineEdit = QLineEdit(self) # designer下的lineEdit,即文本输入框
# 设置伙伴关系
nameLabel.setBuddy(nameLineEdit)
passwordLabel = QLabel('&Password(P)', self) # designer下的label
passwordLineEdit = QLineEdit(self) # designer下的lineEdit,即文本输入框
# 设置伙伴关系
passwordLabel.setBuddy(passwordLineEdit)
btnOK = QPushButton('&OK(O)')
btnCancel = QPushButton('&Cancel(C)')
# 栅格布局
mainlayout = QGridLayout(self)
mainlayout.addWidget(nameLabel, 0, 0) # 放在第一行第一列
# 放在第一行第二列,占用空间大小为一行两列(占用大小一行两列意思就是编辑框宽是标签控件的两倍)
mainlayout.addWidget(nameLineEdit, 0, 1, 1, 2)
mainlayout.addWidget(passwordLabel, 1, 0) # 放在第二行第一列
mainlayout.addWidget(passwordLineEdit, 1, 1, 1, 2) # 放在第二行第二列,占用空间大小为一行两列
mainlayout.addWidget(btnOK, 2, 1) # 第三行第二列
mainlayout.addWidget(btnCancel, 2, 2) # 第三行第三列
return
if __name__ == '__main__':
app = QApplication(sys.argv)
main = QLabelBuddy()
main.show()
sys.exit(app.exec_())
高级功能:EchoMode(回显模式)
基本功能:输入单行文本
4种回显模式:
1.Normal
就是正常的文本框输入,我们输入一个,文本框上就有一个
2.NoEcho
比如Linux下输入密码,输了半天感觉屏幕上啥也没输,但其实输入了,只不过不显示到屏幕上而已
3.Password
就像QQ登录一样,回显但回显的是小黑圆圈,用于输入密码
4.PasswordEchoOnEdit
也是输入密码时,处于编辑时会回显,但离开编辑状态时(比如把鼠标移到别的编辑框时)则变成小黑圆圈
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 14:44
'''
课时32 QLineEdit控件与回显模式(EchoMode)
'''
from PyQt5.QtWidgets import *
import sys
class QLineEditEchoMode(QDialog):
def __init__(self):
super(QLineEditEchoMode, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('文件输入框的回显模式')
self.resize(400, 300)
# 表单布局
formLayout = QFormLayout()
# 创建编辑框
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')
noEchoLineEdit.setPlaceholderText('NoEcho')
passwordLineEdit.setPlaceholderText('Password')
passwordEchoOnEditLineEdit.setPlaceholderText('PasswordEchoOnEdit')
# 设置文本框回显模式
normalLineEdit.setEchoMode(QLineEdit.Normal)
noEchoLineEdit.setEchoMode(QLineEdit.NoEcho)
passwordLineEdit.setEchoMode(QLineEdit.Password)
passwordEchoOnEditLineEdit.setEchoMode(QLineEdit.PasswordEchoOnEdit)
self.setLayout(formLayout)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = QLineEditEchoMode()
main.show()
sys.exit(app.exec_())
校验器
如限制只能输入整数、浮点数或满足一定条件的字符串
代码问题:
限制范围的函数setRange有bug 需要正则表达式解决bug 可能在苹果系统可以(应该也不行) win系统不行
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 15:04 课时33 限制QLineEdi t控件的输入
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QIntValidator, QDoubleValidator, QRegExpValidator # 最后一个是正则表达式校验器
from PyQt5.QtCore import QRegExp # 正则表达式类
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()
formLayout.addRow('整数类型', intLineEdit)
formLayout.addRow('浮点类型', doubleLineEdit)
formLayout.addRow('数字和字母', validatorLineEdit)
intLineEdit.setPlaceholderText('整型[1,99]')
doubleLineEdit.setPlaceholderText('浮点类型[-360,360]')
validatorLineEdit.setPlaceholderText('数字和字母')
# 整数校验器[1,99]
intValidator = QIntValidator(self) # 因为此函数需要一个QWidget对象作为参数,所以把自己传进去了
intValidator.setRange(1, 99) # 试了试可以输入0
# 浮点校验器[-1,360],精度:小数点后2位
doubleValidator = QDoubleValidator(self) # 传self原因同上
doubleValidator.setRange(-1, 360) # setRange有bug 需要正则表达式解决bug 可以在苹果系统可以(没有试过) win系统不行
doubleValidator.setNotation(QDoubleValidator.StandardNotation)
# 设置精度,小数点2位
doubleValidator.setDecimals(2)
# 字符和数字
reg = QRegExp('[a-zA-Z0-9]+$') # 正则表达式
validtor = QRegExpValidator(self) # 传self原因同上
validtor.setRegExp(reg)
# 设置校验器
intLineEdit.setValidator(intValidator)
doubleLineEdit.setValidator(doubleValidator)
validatorLineEdit.setValidator(validtor)
self.setLayout(formLayout)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = QLineEditValidator()
main.show()
sys.exit(app.exec_())
用掩码限制QLineEdit控件的输入
A:ASCII字母字符是必须输入的(A-Z、a-z)
a:ASCII字母字符是允许输入的,但不是必需的(A-Z、a-z)
N:ASCII字母字符是必须输入的(A-Z、a-z、0-9)
n:ASCII字母字符是允许输入的,但不是必需的(A-Z. a-z、0-9)
X:任何字符都是必须输入的
x:任何字符都是允许输入的,但不是必需的
9:ASCII数字字符是必须输入的(0-9)
0:ASCII数字字符是允许输入的,但不是必需的(0-9)
D:ASCII数字字符是必须输入的(1-9)
d:ASCII数字字符是允许输入的,但不是必需的(1-9)
#:ASCII数字字符或加减符号是允许输入的,但不是必需的
H:十六进制格式字符是必须输入的(A-F、a-f、0-9)
h:十六进制格式字符是允许输入的,但不是必需的(A-F、a-f、0-9)
B:二进制格式字符是必须输入的(0, 1)
b:二进制格式字符是允许输入的,但不是必需的(0, 1)
>:所有的字母字符都大写
<:所有字母字符都小写
!:关闭大小写转换
\:使用"\"转义上面列出的字符
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 15:26
import sys
from PyQt5.QtWidgets import *
class QLineEditMask(QWidget):
def __init__(self):
super(QLineEditMask, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('用掩码限制QLineEdit控件的输入')
formLayout = QFormLayout()
ipLineEdit = QLineEdit() # ip地址
macLineEdit = QLineEdit() # MAC地址
dateLineEdit = QLineEdit() # 日期
licenseLineEdit = QLineEdit() # 验证码
#192.168.21.45
# 最后加个分号和_意为没输入是默认显示_ ,前面的都是掩码,即ASCII数字字符是允许输入的,但不是必需的(0-9)
ipLineEdit.setInputMask('000.000.000.000;_')
macLineEdit.setInputMask('HH:HH:HH:HH:HH:HH;_')
dateLineEdit.setInputMask('0000-00-00')
licenseLineEdit.setInputMask('>AAAAA-AAAAA-AAAAA-AAAAA-AAAAA;#') # 若没有输入显示井号
formLayout.addRow('数字掩码', ipLineEdit)
formLayout.addRow('MAC掩码', macLineEdit)
formLayout.addRow('日期掩码', dateLineEdit)
formLayout.addRow('许可证掩码', licenseLineEdit)
self.setLayout(formLayout)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = QLineEditMask()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 15:37
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import Qt
import sys
class QLine_comprehensive_case(QWidget):
def __init__(self):
super(QLine_comprehensive_case, self).__init__()
self.initUI()
def initUI(self):
'''
控件定义及属性设置
'''
edit1 = QLineEdit()
# int校验器
edit1.setValidator(QIntValidator())
# 设置最大位数为4位,即不超过9999
edit1.setMaxLength(4)
# 右对齐
edit1.setAlignment(Qt.AlignRight)
# 这个字号直接影响输入框的尺寸
edit1.setFont(QFont('Arial', 18))
edit2 = QLineEdit()
edit2.setValidator(QDoubleValidator(0.99, 99.99, 2)) # 2是精度,即小数点后几位
edit3 = QLineEdit()
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('Hello Pyqt5!')
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 = QApplication(sys.argv)
main = QLine_comprehensive_case()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 16:30
from PyQt5.QtWidgets import *
import sys
class QTextEditDemo(QWidget):
def __init__(self):
super(QTextEditDemo, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('QTextEdit控件演示')
self.resize(300, 320)
# 定义控件
self.textEdit = QTextEdit()
self.buttonText = QPushButton('显示文本')
self.buttonHTML = QPushButton('显示HTML')
self.buttonToText = QPushButton('获取文本')
self.buttonToHTML = QPushButton('获取HTML')
# 垂直布局
layout = QVBoxLayout()
layout.addWidget(self.textEdit)
layout.addWidget(self.buttonText)
layout.addWidget(self.buttonHTML)
layout.addWidget(self.buttonToText)
layout.addWidget(self.buttonToHTML)
# 绑定信号和槽
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)
self.setLayout(layout)
# 槽函数
def onClick_buttonText(self):
# 普通文本
self.textEdit.setPlainText('Hello World!')
def onClick_buttonHTML(self):
# 富文本(HTML)
self.textEdit.setHtml('Hello World')
def onClick_buttonToText(self):
print(self.textEdit.toPlainText()) # 控制台输出普通文本
def onClick_buttonToHTML(self):
print(self.textEdit.toHtml()) # 控制台输出HTML文本
if __name__ == '__main__':
app = QApplication(sys.argv)
main = QTextEditDemo()
main.show()
sys.exit(app.exec_())
QAbstractButton(所有按钮控件的父类)
QPushButton(普通按钮)
AToolButton(工具条按钮)
QRadioButton(单选框按钮)
QCheckBox(复选框按钮)
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 16:47
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class QPushButtonDemo(QDialog):
def __init__(self):
super(QPushButtonDemo, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('QPushButton Demo')
self.resize(350, 200)
layout = QVBoxLayout() # 垂直布局
self.btn1 = QPushButton('第一个按钮')
self.btn1.setText('First Button1')
# 下面两句配合使用,功能类似于单选框按钮QCheckBox
self.btn1.setCheckable(True)
self.btn1.toggle() # 按一下就按下去了,再按一下才能抬起
# btn1一个信号对应两个槽函数
self.btn1.clicked.connect(self.buttonState) # 先绑定谁系统就先调用谁
self.btn1.clicked.connect(lambda: self.whichButton(self.btn1))
layout.addWidget(self.btn1)
# 在文本前面显示图像
self.btn2 = QPushButton('图像按钮')
self.btn2.setIcon(QIcon(QPixmap('./and.png')))
self.btn2.clicked.connect(lambda: self.whichButton(self.btn2))
layout.addWidget(self.btn2)
self.btn3 = QPushButton('不可用的按钮')
self.btn3.setEnabled(False)
layout.addWidget(self.btn3)
self.btn4 = QPushButton('&MyButton') # 设置了热键M/m
self.btn4.setDefault(True) # 如果没有任何按钮被选中,那么按回车就是按了这个按钮
self.btn4.clicked.connect(lambda: self.whichButton(self.btn4))
layout.addWidget(self.btn4)
self.setLayout(layout)
'''
注意下面的方法是两个参数,如果用传统的信号与槽连接方式的话,只会将按钮对象本身传入,那样的话第二个参数就没有传入值了
所以要用lambda表达式,当前对象直接调用这个函数,传入的值就对应第二个参数了
'''
def whichButton(self, btn):
# self.sender() #通过此方法可得到是哪个按钮被按下,或者可用此方法中的传参方法
print('被单击的按钮是<' + btn.text() + '>')
def buttonState(self):
if self.btn1.isChecked():
print('按钮1已经被选中')
else:
print('按钮1未被选中')
if __name__ == '__main__':
app = QApplication(sys.argv)
main = QPushButtonDemo()
main.show()
sys.exit(app.exec_())
在一个容器内的单选按钮是互斥的,即选中了一个单选按钮,就不能再选中另一个单选按钮,也就是不能同时处于选中状态。在不同容器中的单选按钮是分开的,互不影响。
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 17:12
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
class QRatioButtonDemo(QWidget):
def __init__(self):
super(QRatioButtonDemo, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('QRatioButton')
self.resize(350, 100)
# 水平布局
layout = QHBoxLayout()
self.btn1 = QRadioButton('单选按钮1')
# 设为默认是选中状态
self.btn1.setChecked(True)
# toggled是状态切换的信号
self.btn1.toggled.connect(self.buttonState)
layout.addWidget(self.btn1)
self.btn2 = QRadioButton('单选按钮2')
self.btn2.toggled.connect(self.buttonState)
layout.addWidget(self.btn2)
self.setLayout(layout)
def buttonState(self):
ratiobtn = self.sender()
if ratiobtn.isChecked() == True:
print('<' + ratiobtn.text() + '>被选中')
else:
print('<' + ratiobtn.text() + '>被取消选中状态')
# 同一容器下单选按钮是互斥的,所以不必利用ratiobtn.text()来分情况判断
'''
if ratiobtn.text()=='单选按钮1':
#是否被选中
if ratiobtn.isChecked()==True:
print('<'+ratiobtn.text()+'>被选中')
else:
print('<'+ratiobtn.text()+'>被取消选中状态')
if ratiobtn.text()=='单选按钮2':
if ratiobtn.isChecked()==True:
print('<'+ratiobtn.text()+'>被选中')
else:
print('<'+ratiobtn.text()+'>被取消选中状态')
'''
if __name__ == '__main__':
app = QApplication(sys.argv)
main = QRatioButtonDemo()
main.show()
sys.exit(app.exec_())
3种状态:
未选中:0
半选中:1
选中:2
tristate属性表示复选框是三种状态还是两种状态,如果tristate为true,则表示复选框中有选中,半选中,未选中三种状态,即setTristate(True)即表示允许半选中。
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 17:39
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtCore import Qt # 其中有许多常量
class QCheckBoxDemo(QWidget):
def __init__(self):
super(QCheckBoxDemo, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('QCheckBoxDemo')
self.resize(350, 100)
layout = QHBoxLayout()
self.checkbox1 = QCheckBox('复选框控件1')
# 默认选中
self.checkbox1.setChecked(True) # 此函数只有两种状态
self.checkbox1.stateChanged.connect(lambda: self.checkboxState(self.checkbox1))
layout.addWidget(self.checkbox1)
self.checkbox2 = QCheckBox('复选框控件2')
self.checkbox2.stateChanged.connect(lambda: self.checkboxState(self.checkbox2))
layout.addWidget(self.checkbox2)
self.checkbox3 = QCheckBox('半选中控件3')
# 设置选中有三个状态(即允许半选中)
self.checkbox3.setTristate(True)
# setCheckState函数有三种状态:Unchecked,PartiallyChecked,Checked
self.checkbox3.setCheckState(Qt.PartiallyChecked)
self.checkbox3.stateChanged.connect(lambda: self.checkboxState(self.checkbox3))
layout.addWidget(self.checkbox3)
self.setLayout(layout)
def checkboxState(self, cb):
check1Status = self.checkbox1.text() + ',isChecked=' + str(self.checkbox1.isChecked()) + ',isCheckstate=' + str(
self.checkbox1.checkState()) + '\n'
check2Status = self.checkbox2.text() + ',isChecked=' + str(self.checkbox2.isChecked()) + ',isCheckstate' + str(
self.checkbox2.checkState()) + '\n'
check3Status = self.checkbox3.text() + ',isChecked=' + str(self.checkbox3.isChecked()) + ',isCheckstate' + str(
self.checkbox3.checkState()) + '\n'
print(check1Status + check2Status + check3Status)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = QCheckBoxDemo()
main.show()
sys.exit(app.exec_())
1 如何将列表项添加到QComboBox控件中
2 如何获取选中的列表项
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 17:56
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtCore import Qt # 其中有许多常量
class QComboBoxDemo(QWidget):
def __init__(self):
super(QComboBoxDemo, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('QComboBoxDemo')
self.resize(350, 100)
# 垂直布局
layout = QVBoxLayout()
self.label = QLabel('请选择编程语言')
self.cb = QComboBox()
self.cb.addItem('JavaEE')
self.cb.addItem('Uniapp')
self.cb.addItems(['Python', '大数据', '区块链'])
# 每一项都对应一个下标索引
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 j in range(self.cb.count()):
print('item' + str(j) + '=' + self.cb.itemText(j))
print('current index', i, 'selection changed', self.cb.currentText())
if __name__ == '__main__':
app = QApplication(sys.argv)
main = QComboBoxDemo()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 18:20
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import Qt # 其中有许多常量
class QSliderDemo(QWidget):
def __init__(self):
super(QSliderDemo, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('QSlider演示')
self.resize(350, 500)
# 垂直布局
layout = QVBoxLayout()
self.label = QLabel('Hello PyQt5!')
self.label.setAlignment(Qt.AlignCenter)
layout.addWidget(self.label)
# 滑块分为水平和垂直两种
# 水平slider1
self.slider1 = QSlider(Qt.Horizontal) # 水平,左右滑动
# 设置最小值
self.slider1.setMinimum(12)
# 设置最大值
self.slider1.setMaximum(48)
# 步长
self.slider1.setSingleStep(3)
# 设置当前值
self.slider1.setValue(18)
# 设置刻度的位置,刻度在下方
self.slider1.setTickPosition(QSlider.TicksBelow)
# 刻度间隔
self.slider1.setTickInterval(6)
self.slider1.valueChanged.connect(self.valueChange)
# 垂直slider2
self.slider2 = QSlider(Qt.Vertical) # 垂直滑块
self.slider2.setMinimum(1)
self.slider2.setMaximum(80)
self.slider2.setSingleStep(5)
self.slider2.setTickPosition(QSlider.TicksLeft) # 刻度条放在滑块的左边
self.slider2.setTickInterval(10)
self.slider2.valueChanged.connect(self.valueChange)
layout.addWidget(self.slider1)
layout.addWidget(self.slider2)
self.setLayout(layout)
def valueChange(self):
'''
注意这里是sender(),而不是slider1也不是slider2,sender()获取当前操作的控件,
这样无论拖动哪个滑动条字体大小都会变化,因为这俩信号对应这一个槽函数
'''
print('当前值:%s' % self.sender().value())
size = self.sender().value() # 获得当前值
# 使字号根据当前值来变化
self.label.setFont(QFont('Arial', size))
if __name__ == '__main__':
app = QApplication(sys.argv)
main = QSliderDemo()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 18:34
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import Qt # 其中有许多常量
class QSpinBoxDemo(QWidget):
def __init__(self):
super(QSpinBoxDemo, self).__init__()
self.initUI()
def initUI(self):
####################################### 窗口设置
self.setWindowTitle('QSliderDemo')
self.resize(350, 120)
# 垂直布局
layout = QVBoxLayout()
######################################## 控件
self.label = QLabel('当前值')
self.label.setAlignment(Qt.AlignCenter)
self.sb = QSpinBox()
# 默认值
self.sb.setValue(18)
# 设置范围
self.sb.setRange(10, 38)
# 设置步长
self.sb.setSingleStep(3)
####################################### 信号与槽
self.sb.valueChanged.connect(self.valueChange)
####################################### 组装
layout.addWidget(self.label)
layout.addWidget(self.sb)
self.setLayout(layout)
def valueChange(self):
self.label.setText('当前值:' + str(self.sb.value()))
if __name__ == '__main__':
app = QApplication(sys.argv)
main = QSpinBoxDemo()
main.show()
sys.exit(app.exec_())
QMessageBox 消息对话框
QColorDialog 颜色对话框
QFileDialog 文件对话框
QFontDia log 字体对话框
QInputDialog 输入对话框(获取输入信息)
主要用于显示软件的版本和作者及其他和软件息息相关的信息
常用的消息对话框:
1.关于对话框
2.错误对话框
3.警告对话框
4.提问对话框
5.消息对话框
有2点差异
1.显示的对话框图标可能不同
2.显示的按钮是不一样的
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 19:18
import sys
from PyQt5.QtWidgets import *
class QMessageBoxDemo(QWidget):
def __init__(self):
super(QMessageBoxDemo, self).__init__()
self.initUI()
def initUI(self):
# 窗口设置
self.setWindowTitle('QMessageBoxDemo')
self.resize(400, 300)
# 控件
self.btn1 = QPushButton()
self.btn1.setText('显示关于对话框')
self.btn2 = QPushButton()
self.btn2.setText('显示消息对话框')
self.btn3 = QPushButton()
self.btn3.setText('显示警告对话框')
self.btn4 = QPushButton()
self.btn4.setText('显示错误对话框')
self.btn5 = QPushButton()
'''
一般是提问用户,让用户做出选择
比如关闭一个正在编辑的文件,如果没有保存,软件会提示你是否保存
或者要覆盖一个文件的话,会提示是否要覆盖等
'''
self.btn5.setText('显示提问对话框')
# 信号与槽绑定
self.btn1.clicked.connect(self.showDialog)
self.btn2.clicked.connect(self.showDialog)
self.btn3.clicked.connect(self.showDialog)
self.btn4.clicked.connect(self.showDialog)
self.btn5.clicked.connect(self.showDialog)
# 布局
layout = QVBoxLayout()
layout.addWidget(self.btn1)
layout.addWidget(self.btn2)
layout.addWidget(self.btn3)
layout.addWidget(self.btn4)
layout.addWidget(self.btn5)
self.setLayout(layout)
# 槽函数
def showDialog(self):
text = self.sender().text()
if text == '显示关于对话框':
QMessageBox.about(self, '关于', '这是一个关于对话框')
elif text == '显示消息对话框':
'''
第二个参数是窗口名,第三个参数是窗口内容
最后一个参数是默认的,什么也不做,按回车就执行默认选项
'''
reply = 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_())
QInputDialog.getItem 用于显示输入列表,即往里传入一个元组或列表,就会显示一个QComboBox
QInputDialog.getText 用于录入普通文本
QInputDialog.getInt 用于输入整数的,显示一个计数器控件
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 19:38
import sys
from PyQt5.QtWidgets import *
class QInputDialogDemo(QWidget):
def __init__(self):
super(QInputDialogDemo, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('QInputDialogDemo')
self.resize(400, 150)
# 表单布局
layout = QFormLayout()
self.btn1 = QPushButton('获取列表中的选项')
self.btn1.clicked.connect(self.getItem)
self.lineEdit1 = QLineEdit()
layout.addRow(self.btn1, self.lineEdit1)
self.btn2 = QPushButton('获取字符串')
self.btn2.clicked.connect(self.getText)
self.lineEdit2 = QLineEdit()
layout.addRow(self.btn2, self.lineEdit2)
self.btn3 = QPushButton('获取整数')
self.btn3.clicked.connect(self.getInt)
self.lineEdit3 = QLineEdit()
layout.addRow(self.btn3, self.lineEdit3)
self.setLayout(layout)
# 槽函数
# 下拉框
def getItem(self):
items = ('JavaEE', 'Uniapp', '大数据', '区块链', '人工智能')
# 返回的是个元组,第一个元素就是input里对应的内容,第二个元素是个布尔量,如果对话框是按OK则返回1,取消就是返回0
item, ok = QInputDialog.getItem(self, '请选择技术方向', '技术列表', items)
print(ok) # 点了OK就返回True,点了Cancel就返回False
if ok and item:
self.lineEdit1.setText(item)
print(ok)
# 字符串
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_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 19:52
import sys
from PyQt5.QtWidgets import *
class QFontDialogDemo(QWidget):
def __init__(self):
super(QFontDialogDemo, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('QFontDialogDemo')
self.resize(400, 150)
layout = QVBoxLayout()
self.fontBtn = QPushButton('选择字体')
self.fontBtn.clicked.connect(self.getFont)
layout.addWidget(self.fontBtn)
self.fontLabel = QLabel('Hello,测试字体例子')
layout.addWidget(self.fontLabel)
self.setLayout(layout)
def getFont(self):
(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_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 19:59
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QPalette
class QColorDialogDemo(QWidget):
def __init__(self):
super(QColorDialogDemo, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('QColorDialogDemo')
self.resize(400, 150)
layout = QVBoxLayout()
self.colorBtn = QPushButton('设置颜色')
self.colorBtn.clicked.connect(self.getColor)
layout.addWidget(self.colorBtn)
self.colorBackBtn = QPushButton('设置背景颜色')
self.colorBackBtn.clicked.connect(self.getBackColor)
layout.addWidget(self.colorBackBtn)
self.colorLabel = QLabel('Hello,测试颜色例子')
layout.addWidget(self.colorLabel)
self.setLayout(layout)
def getColor(self):
color = QColorDialog.getColor()
# 调色板
p = QPalette()
# 注意WindowText(这是类属性,常量)的大小写,这是常量,别选错了!!!!
p.setColor(QPalette.WindowText, color)
print('QPalette.WindowText =', QPalette.WindowText)
print('QPalette.Window =', QPalette.Window)
self.colorLabel.setPalette(p)
# 设置背景颜色
def getBackColor(self):
color = QColorDialog.getColor()
p = QPalette()
p.setColor(QPalette.Window, color)
# 自动填充背景
self.colorLabel.setAutoFillBackground(True)
self.colorLabel.setPalette(p)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = QColorDialogDemo()
main.show()
sys.exit(app.exec_())
绘图API: 绘制文本
1.文本
2.各种图形(直线,点,椭圆,弧,扇形,多边形等)
3.图像QPainter过程:
painter = QPainter() #创建绘制对象
painter. begin() #开始绘制
painter. drawText(...) #绘制过程
painter. end() #结束绘制
必须在paintEvent事件方法(此方法窗口自动调用,创建窗口或窗口尺寸变化时)中绘制各种元素
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 20:29
import sys
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtGui import QPainter, QColor, QFont
from PyQt5.QtCore import Qt
class DrawText(QWidget):
def __init__(self):
super(DrawText, self).__init__()
self.setWindowTitle('在窗口上绘制文本')
self.resize(300, 200)
self.text = 'CSDN王家视频教程图书馆'
def paintEvent(self, event):
painter = QPainter(self)
painter.begin(self)
print('窗口大小改变,此方法会不断调用')
# 画笔
painter.setPen(QColor(150, 43, 5)) # RGB
# 字体,字号
painter.setFont(QFont('SimSun', 25))
# 绘图区域,居中,绘制文本
painter.drawText(event.rect(), Qt.AlignCenter, self.text)
painter.end()
if __name__ == '__main__':
app = QApplication(sys.argv)
main = DrawText()
main.show()
sys.exit(app.exec_())
#核心代码参考
for i in range(1000):
x = 100 * (-1 + 2.0 * i / 1000) + size.width() / 2.0 # 加上size.width()/2.0是将绘制图像原点挪到窗口中间
y = -50 * math.sin((x - size.width() / 2.0) * math.pi / 50) + size.height() / 2.0
painter.drawPoint(x, y) # 说是曲线,其实是画了1000个点,看上去有点像曲线
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 20:34
'''
用像素点绘制正弦曲线
-2PI 2PI
drawPoint(x,y)
'''
import sys, math
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import Qt
class DrawPoints(QWidget):
def __init__(self):
super(DrawPoints, self).__init__()
self.resize(500, 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 # 加上size.width()/2.0是将绘制图像原点挪到窗口中间
y = -50 * math.sin((x - size.width() / 2.0) * math.pi / 50) + size.height() / 2.0
painter.drawPoint(x, y) # 说是曲线,其实是画了1000个点,看上去有点像曲线
painter.end() # 结束画图
if __name__ == '__main__':
app = QApplication(sys.argv)
main = DrawPoints()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 20:22
import sys
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtGui import QPainter, QColor, QFont, QPen
from PyQt5.QtCore import Qt
class DrawMutilLine(QWidget):
def __init__(self):
super(DrawMutilLine, self).__init__()
self.setWindowTitle('设置Pen的样式')
self.resize(350, 250)
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) # 切记设置完style之后,要再将pen设置一遍,否则不会起作用
painter.drawLine(20, 80, 250, 80)
pen.setStyle(Qt.DashDotDotLine)
painter.setPen(pen)
painter.drawLine(20, 120, 250, 120)
pen.setStyle(Qt.DotLine)
painter.setPen(pen)
painter.drawLine(20, 160, 250, 160)
pen.setStyle(Qt.CustomDashLine)
pen.setDashPattern([1, 10, 5, 10]) # 线长度,间隔长度,线长度,间隔长度
painter.setPen(pen)
painter.drawLine(20, 200, 250, 200)
painter.end()
if __name__ == '__main__':
app = QApplication(sys.argv)
main = DrawMutilLine()
main.show()
sys.exit(app.exec_())
绘制各种图形
弧
圆形
椭圆
矩形(正方形)
多边形
绘制图像
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 20:47
import sys
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtGui import QPainter, QPolygon, QImage
from PyQt5.QtCore import Qt, QRect, QPoint
import os
class DrawAll(QWidget):
def __init__(self):
super(DrawAll, self).__init__()
self.setWindowTitle('绘制各种图形')
self.resize(400, 600)
def paintEvent(self, event):
qp = QPainter(self)
qp.begin(self)
qp.setPen(Qt.blue)
# 绘制弧
# 左上角坐标,宽,高
rect = QRect(0, 10, 200, 200)
# 绘制区域(在其中绘制,起始角度,结束角度)
# alen:一个alen等于1/16度,eg:画45°的弧就是45*16
qp.drawArc(rect, 0, 50 * 16)
# 通过弧绘制圆
qp.setPen(Qt.red)
# rect也可直接当参数传进去
qp.drawArc(120, 10, 100, 100, 0, 360 * 16)
# 绘制带弦的弧
rect1 = QRect(10, 120, 100, 100)
qp.drawChord(rect1, 12, 130 * 16)
# 绘制扇形
rect2 = QRect(10, 240, 100, 100)
qp.drawPie(rect2, 12, 130 * 16)
# 椭圆(不需要指定角度)
# 宽和高肯定是不一样的,如果一样就是圆了,所以绘制圆可以通过椭圆,也可以通过弧
qp.drawEllipse(120, 120, 150, 100)
# 绘制多边形
# 五边形,需要五个点
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)
# 绘制图像
print(os.path.exists('./and.png')) # 此路径是否存在
# 装载图像
image = QImage('./and.png')
# 将图像(面积)缩小64倍
rect3 = QRect(10, 400, image.width() / 8, image.height() / 8)
qp.drawImage(rect3, image)
qp.end()
if __name__ == '__main__':
app = QApplication(sys.argv)
main = DrawAll()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 21:02
import sys
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtGui import QPainter, QPolygon, QImage, QBrush
from PyQt5.QtCore import Qt, QRect, QPoint
class FillRect(QWidget):
def __init__(self):
super(FillRect, self).__init__()
self.setWindowTitle('绘制各种图形')
self.resize(400, 200)
def paintEvent(self, event):
qp = QPainter(self)
qp.begin(self)
brush = QBrush(Qt.SolidPattern) # 实心
qp.setBrush(brush)
qp.drawRect(10, 15, 90, 60)
brush = QBrush(Qt.Dense1Pattern)
qp.setBrush(brush)
qp.drawRect(130, 15, 90, 60)
brush = QBrush(Qt.Dense2Pattern)
qp.setBrush(brush)
qp.drawRect(250, 15, 90, 60)
brush = QBrush(Qt.Dense3Pattern)
qp.setBrush(brush)
qp.drawRect(10, 105, 90, 60)
brush = QBrush(Qt.HorPattern)
qp.setBrush(brush)
qp.drawRect(130, 105, 90, 60)
qp.end()
if __name__ == '__main__':
app = QApplication(sys.argv)
main = FillRect()
main.show()
sys.exit(app.exec_())
过程:
A.setDrapEnabled(True) 设置A支持拖拽
B. setAcceptDrops(True) 设置B可接收
B需要两个事件:
1. dragEnterEvent 将A拖到B触发
2. dropEvent 在B的区域放下A时触发
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 21:10
import sys
from PyQt5.QtWidgets import *
# 下拉框类
class MyComboBox(QComboBox):
def __init__(self):
super(MyComboBox, self).__init__()
# 设置下拉框可接收
self.setAcceptDrops(True)
# 别的控件拖进来以后,还没松鼠标时,下面的函数触发
def dragEnterEvent(self, e):
print(e)
# 是否是文本
if e.mimeData().hasText():
e.accept()
else:
e.ignore()
# 当控件拖进来放下时,下面的函数触发
def dropEvent(self, e):
# 此时self代表当前下拉列表控件,
self.addItem(e.mimeData().text())
class DragDropDemo(QWidget):
def __init__(self):
super(DragDropDemo, self).__init__()
formLayout = QFormLayout()
formLayout.addRow(QLabel('请将左边的文本拖到右边的下拉列表中'))
lineEdit = QLineEdit()
# 让QLinEdit控件可拖动
lineEdit.setDragEnabled(True)
# 第一个类MyComboBox的实例
combo = MyComboBox()
formLayout.addRow(lineEdit, combo)
self.setLayout(formLayout)
self.setWindowTitle('拖拽案例')
self.resize(400, 100)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = DragDropDemo()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 21:22
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
class ClipBoardDemo(QDialog):
def __init__(self):
super(ClipBoardDemo, self).__init__()
# 控件
# 定义六个复制粘贴按钮,用来实现复制粘贴文本,图像和HTML网页
textCopyBtn = QPushButton('复制文本')
textPasteBtn = QPushButton('粘贴文本')
htmlCopyBtn = QPushButton('复制HTML')
htmlPasteBtn = QPushButton('粘贴HTML')
imageCopyBtn = QPushButton('复制图像')
imagePasteBtn = QPushButton('粘贴图像')
# 多行文本
self.textLabel = QLabel('默认文本')
# 标签用于展示图片
self.imageLabel = QLabel()
# 定义网格栅格布局
layout = QGridLayout()
layout.addWidget(textCopyBtn, 0, 0)
layout.addWidget(imageCopyBtn, 0, 1)
layout.addWidget(htmlCopyBtn, 0, 2)
layout.addWidget(textPasteBtn, 1, 0)
layout.addWidget(imagePasteBtn, 1, 1)
layout.addWidget(htmlPasteBtn, 1, 2)
layout.addWidget(self.textLabel, 2, 0, 1, 2) # 坐标,行占的单位宽度,列占的单位宽度
layout.addWidget(self.imageLabel, 2, 2)
self.setLayout(layout)
# 信号与槽
textCopyBtn.clicked.connect(self.copyText)
textPasteBtn.clicked.connect(self.pasteText)
htmlCopyBtn.clicked.connect(self.copyHtml)
htmlPasteBtn.clicked.connect(self.pasteHtml)
imageCopyBtn.clicked.connect(self.copyImage)
imagePasteBtn.clicked.connect(self.pasteImage)
self.setWindowTitle('剪贴板演示')
# 槽函数
def copyText(self):
# 剪贴板对象
clipboard = QApplication.clipboard()
clipboard.setText('hello csdn')
def pasteText(self):
clipboard = QApplication.clipboard()
self.textLabel.setText(clipboard.text())
def copyImage(self):
clipboard = QApplication.clipboard()
clipboard.setPixmap(QPixmap('./csdnlogo.jpg'))
def pasteImage(self):
clipboard = QApplication.clipboard()
# clipboard.pixmap()是从剪贴板获得图像
self.imageLabel.setPixmap(clipboard.pixmap())
def copyHtml(self):
mimeData = QMimeData() # 获得数据类型
mimeData.setHtml('Bold and Red')
clipboard = QApplication.clipboard()
clipboard.setMimeData(mimeData)
def pasteHtml(self):
clipboard = QApplication.clipboard()
mimeData = clipboard.mimeData() # 获得剪贴板数据
# 如果剪贴板数据是html,这里普通文本也可以
if mimeData.hasHtml():
self.textLabel.setText(mimeData.html())
if __name__ == '__main__':
app = QApplication(sys.argv)
main = ClipBoardDemo()
main.show()
sys.exit(app.exec_())
日历控件:QCalendarWidget
控件:QDateTimeEdit
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 21:39
import sys
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):
# 垂直布局
vlayout = QVBoxLayout()
dateTimeEdit1 = QDateTimeEdit()
dateTimeEdit2 = QDateTimeEdit(QDateTime.currentDateTimeUtc()) # 传入当前时间
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')
vlayout.addWidget(dateTimeEdit1)
vlayout.addWidget(dateTimeEdit2)
vlayout.addWidget(dateEdit)
vlayout.addWidget(timeEdit)
self.setLayout(vlayout)
self.resize(300, 90)
self.setWindowTitle('设置不同风格的日期和时间')
if __name__ == '__main__':
app = QApplication(sys.argv)
main = DateTimeEdit1()
main.show()
sys.exit(app.exec_())
方法 描述
setDisplayFormat 设置日期的时间格式
yyyy:代表年份,用4为数表示
MM:代表月份,取值范围01-12
dd:代表日,取值范围01-31
HH:代表小时,取值范围00-23
mm:代表分钟,取值范围00-59
ss:代表秒,取值范围00-59
setMinimumDate() 设置控件的最小日期
setMaximumDate() 设置控件的最大日期
time() 返回编辑的时间
date() 返回编辑的日期
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 21:55
import sys
from PyQt5.QtWidgets import *
class Menu(QMainWindow):
def __init__(self):
super(Menu, self).__init__()
bar = self.menuBar()
file = bar.addMenu('文件') # 顶层菜单栏
# 文件的子菜单(方法一:直接传文本,内部会自动创建动作QAction)
file.addAction('新建')
# 法二:自己用动作来创建子菜单
save = QAction('保存', self) # 必须加self,代表在当前窗口加QAction
save.setShortcut('Ctrl+S') # 快捷键
file.addAction(save)
quit = QAction('退出', self)
file.addAction(quit)
edit = bar.addMenu('Edit') # 顶层菜单
edit.addAction('copy') # 子菜单
edit.addAction('paste')
save.triggered.connect(self.process)
self.resize(400, 300)
# 槽函数
# 事件自动传给槽函数的一个实参,在本例具体指的是菜单项是否被选中,是一个bool类型的值
def process(self, a):
print(self.sender().text()) # 注意这里是self.而不是a.
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Menu()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 22:06
import sys
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') # 一行工具栏
'''
工具栏默认按钮:只显示图标,将文本作为悬停提示
即鼠标悬停到图标上之后,提示就是下面的第二个参数
'''
new = QAction(QIcon('./csdnlogo.jpg'), '新建', self) # self代表放在当前窗口上
tb1.addAction(new)
open = QAction(QIcon('./csdnlogo.jpg'), '打开', self)
tb1.addAction(open)
save = QAction(QIcon('./csdnlogo.jpg'), '保存', self)
tb1.addAction(save)
'''
工具栏按钮有3种显示状态
1.只显示图标
2.只显示文本
3.同时显示文本和图标
'''
# 设置工具栏按钮显示状态:既显示文本又显示图标
tb1.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) # 设置文本在图标的下方显示,还有好多,按ctrl查看自己试试
tb2 = self.addToolBar('File1')
new1 = QAction(QIcon('./csdnlogo.jpg'), '新建', self)
tb2.addAction(new1)
tb2.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
tb1.actionTriggered.connect(self.toolbtnpressed)
tb2.actionTriggered.connect(self.toolbtnpressed)
def toolbtnpressed(self, a):
print('按下的工具栏按钮是', a.text())
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Toolbar()
main.show()
sys.exit(app.exec_())
用于显示状态信息,一般在窗口的最下方显示
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 22:16
import sys
from PyQt5.QtWidgets import *
class Statusbar(QMainWindow):
def __init__(self):
super(Statusbar, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('状态栏演示')
self.resize(300, 200)
bar = self.menuBar() # 顶层菜单栏
file = bar.addMenu('File') # 给菜单栏添加选项
file.addAction('show') # 子菜单
file.triggered.connect(self.processTrigger)
self.setCentralWidget(QTextEdit()) # 多行输入
self.statusBar = QStatusBar()
self.setStatusBar(self.statusBar)
def processTrigger(self, q):
if q.text() == 'show':
# 在状态栏上显示信息
self.statusBar.showMessage(q.text() + '菜单被点击了', 5000) # 信息显示5秒
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Statusbar()
main.show()
sys.exit(app.exec_())
输出都是以图像形式输出,输出到打印机
链接打印机开始打印 这里就不测试打印机了!
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 22:21
import sys
from PyQt5.QtWidgets import *
from PyQt5 import QtGui, QtPrintSupport
class PrintSupport(QMainWindow):
def __init__(self):
super(PrintSupport, self).__init__()
self.setGeometry(500, 200, 300, 300)
self.btn = QPushButton('打印QTextEdit控件中的内容', self)
self.btn.setGeometry(20, 20, 260, 30) # x,y,w,h
self.editor = QTextEdit('默认文本', self)
self.editor.setGeometry(20, 60, 260, 200)
self.btn.clicked.connect(self.print)
def print(self):
# 打印机对象
printer = QtPrintSupport.QPrinter()
painter = QtGui.QPainter()
# 将绘制的目标重定向到打印机上
painter.begin(printer) # painter画在begin的参数上,即printer上,若是self,则画在当前窗口上
# 获得多行输入控件editor的整个框架
screen = self.editor.grab()
# 从(10,10)开始将screen上的文字输出到打印机上
# drawPixmap:从图像文件中提取 Pixmap 并将其显示在指定位置
painter.drawPixmap(10, 10, screen)
painter.end()
print('print')
if __name__ == '__main__':
app = QApplication(sys.argv)
main = PrintSupport()
main.show()
sys.exit(app.exec_())
因为没有打印机 但是可以输出为pdf文档
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 22:26
import sys
from PyQt5.QtPrintSupport import QPrinter, QPageSetupDialog, QPrintDialog
from PyQt5.QtWidgets import *
class PrintDialog(QMainWindow):
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)
self.openButton = QPushButton('打开文件', self)
self.openButton.move(350, 20)
self.settingButton = QPushButton('打印设置', self)
self.settingButton.move(350, 50)
self.printButton = QPushButton('打印文档', self)
self.printButton.move(350, 80)
self.openButton.clicked.connect(self.openFile)
self.settingButton.clicked.connect(self.showSettingDialog)
self.printButton.clicked.connect(self.showPrintDialog)
# 打开文件
def openFile(self):
fname = QFileDialog.getOpenFileName(self, '打开文本文件', './')
print(fname)
print(fname[0])
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):
printdailog = QPrintDialog(self.printer, self)
if QDialog.Accepted == printdailog.exec():
# 将editor里的文字输出到打印机中
self.editor.print(self.printer)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = PrintDialog()
main.show()
sys.exit(app.exec_())
显示二维表数据(QTableVi ew控件)
数据源 Model
需要创建QTableView实例和一个数据源(Model) ,然后将两者关联,这个体系类似于MVC模式。
一个QTableView实例可以存放不同的数据源,一个数据源也可以对应不同的QTableView实例。
MVC: Model Viewer Controller 即将数据Model和前端视图Viewer分离,通过控制器Controller 来控制。
MVC的目的是将后端的数据和前端页面的耦合度降低。
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 22:36
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)
self.model = QStandardItemModel(4, 3) # 二维表4行3列
# 数据表的字段
self.model.setHorizontalHeaderLabels(['id', 'name', 'age'])
self.tableView = QTableView()
# 关联QTableView控件和Model
self.tableView.setModel(self.model)
# 添加数据
item11 = QStandardItem('1') # 一个QStandardItem就是一个单元格
item12 = QStandardItem('Kobe')
item13 = QStandardItem('24')
self.model.setItem(0, 0, item11)
self.model.setItem(0, 1, item12)
self.model.setItem(0, 2, item13)
# 可跳行添加数据
item31 = QStandardItem('7')
item32 = QStandardItem('Durant')
item33 = QStandardItem('35')
self.model.setItem(2, 0, item31)
self.model.setItem(2, 1, item32)
self.model.setItem(2, 2, item33)
# 垂直布局
layout = QVBoxLayout()
layout.addWidget(self.tableView)
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = TableView()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 22:46
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import QStringListModel
class ListView(QWidget):
def __init__(self):
super(ListView, self).__init__()
self.setWindowTitle('ListView例子')
self.resize(300, 270)
layout = QVBoxLayout()
listView = QListView()
# 数据源
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)
main = ListView()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 22:50
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import QStringListModel
'''
QListWidget是QListView的子类
添加了很多API,支持MVC模式,也支持非MVC模式,即数据直接添加到控件上
'''
class ListWidget(QMainWindow):
def __init__(self):
super(ListWidget, self).__init__()
self.setWindowTitle('ListWidget例子')
self.resize(300, 270)
# 直接添加的方式适合少量的数据的时候
self.listWidget = QListWidget()
# self.listWidget.resize(300,120)
self.listWidget.addItem('item1')
self.listWidget.addItem('item2')
self.listWidget.addItem('item3')
self.listWidget.addItem('item4')
self.listWidget.addItem('item5')
self.listWidget.itemClicked.connect(self.clicked)
# 设置中心控件之后,会铺满整个屏幕,无需再单独设置listWidget尺寸
self.setCentralWidget(self.listWidget)
def clicked(self, index):
QMessageBox.information(self, 'ListWidget',
'您选择了:' + self.listWidget.item(self.listWidget.row(index)).text())
if __name__ == '__main__':
app = QApplication(sys.argv)
main = ListWidget()
main.show()
sys.exit(app.exec_())
每一个Cell (单元格) 是一个QTableWidgetItem
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 22:52
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
'''
QTableWidget是QTableView的子类
添加了很多API,支持MVC模式,也支持非MVC模式,即数据直接添加到控件上
'''
class TableWidget(QWidget):
def __init__(self):
super(TableWidget, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('QTableWidget演示')
self.resize(430, 230)
layout = QHBoxLayout()
tablewidget = QTableWidget()
# 4行3列
tablewidget.setRowCount(4)
tablewidget.setColumnCount(3)
tablewidget.setHorizontalHeaderLabels(['name', 'age', 'address'])
nameItem = QTableWidgetItem('文龙')
tablewidget.setItem(0, 0, nameItem)
ageItem = QTableWidgetItem('23')
tablewidget.setItem(0, 1, ageItem)
addressItem = QTableWidgetItem('北京')
tablewidget.setItem(0, 2, addressItem)
# 禁止编辑
tablewidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
# 整行选择
tablewidget.setSelectionBehavior(QAbstractItemView.SelectRows)
# 调整列和行
tablewidget.resizeColumnsToContents()
tablewidget.resizeRowsToContents()
# 隐藏表格头
tablewidget.horizontalHeader().setVisible(False) # 隐藏水平方向的表格头
# tablewidget.verticalHeader().setVisible(False) #隐藏垂直方向的表格头
# 设置表格头内容
tablewidget.setVerticalHeaderLabels(['a', 'b']) # 垂直方向表格头前两个设为a,b
# 隐藏表格线
tablewidget.setShowGrid(False)
layout.addWidget(tablewidget)
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = TableWidget()
main.show()
sys.exit(app.exec_())
在单元格中放置控件
setItem:将文本放到单元格中
setCellWidget:将控件放到单元格中
setStyleSheet设置控件的样式(QSS)
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 22:57
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
'''
QTableWidget是QTableView的子类
添加了很多API,支持MVC模式,也支持非MVC模式,即数据直接添加到控件上
'''
class TableWidget2(QWidget):
def __init__(self):
super(TableWidget2, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('在单元格中放置控件')
self.resize(430, 300)
layout = QHBoxLayout()
tableWidget = QTableWidget()
# 4行3列
tableWidget.setRowCount(4)
tableWidget.setColumnCount(3)
tableWidget.setHorizontalHeaderLabels(['name', 'age', 'weigh(kg)'])
textItem = QTableWidgetItem('小明')
# setItem:将文本放到单元格中
tableWidget.setItem(0, 0, textItem)
# 下拉框
combox = QComboBox()
combox.addItem('男')
combox.addItem('女')
# setStyleSheet设置控件的样式(QSS)(类似于web中的CSS),即Qt StyleSheet(n.样式表)
combox.setStyleSheet('QComboBox{margin:3px};') # 设置控键距离上下左右的单元格的距离(距离)
# setCellWidget:将控件放到单元格中
tableWidget.setCellWidget(0, 1, combox)
modifyButton = QPushButton('修改')
# 默认是按下的状态
modifyButton.setDown(True)
modifyButton.setStyleSheet('QPushButton{margin:3px};')
tableWidget.setCellWidget(0, 2, modifyButton)
layout.addWidget(tableWidget)
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = TableWidget2()
main.show()
sys.exit(app.exec_())
在表格中快速定位到特定的行
1.数据的定位: findItems ,返回一个列表
2.如果找到了满足条件的单元格,会定位到单元格所在的行: setSliderPosition(row)
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 23:03
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class DataLocation(QWidget):
def __init__(self):
super(DataLocation, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('在表格中搜索Cell和行定位')
self.resize(600, 800)
layout = QHBoxLayout()
tableWidget = QTableWidget()
tableWidget.setRowCount(40)
tableWidget.setColumnCount(4)
for i in range(40):
for j in range(4):
itemContent = '(%d,%d)' % (i, j)
tableWidget.setItem(i, j, QTableWidgetItem(itemContent))
self.setLayout(layout)
# 搜索满足条件的Cell
text = '(13,1)'
text1 = '(1,'
# 参数一:要匹配的文本 ; 参数二:搜索模式,返回一个列表
# items=tableWidget.findItems(text,Qt.MatchExactly)#搜索模式设为精确匹配,必须一模一样才行
items = tableWidget.findItems(text1, Qt.MatchStartsWith) # 搜索模式为匹配以...为开头的字符串,这里看text1,即以(1,开头的的字符串
length = len(items)
if length > 0:
print('匹配项个数:', len(items))
for i in range(length):
item = items[i]
# 背景色
item.setBackground(QBrush(QColor(0, 255, 0))) # rgb
# 前景色,即文字的颜色
item.setForeground(QBrush(QColor(255, 0, 0)))
# 当前项所在的行
row = item.row()
# 定位到指定的行
tableWidget.verticalScrollBar().setSliderPosition(row)
layout.addWidget(tableWidget)
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = DataLocation()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 23:19
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class CellFontAndColor(QWidget):
def __init__(self):
super(CellFontAndColor, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('设置单元格字体和颜色')
self.resize(430, 230)
layout = QHBoxLayout()
tableWidget = QTableWidget()
tableWidget.setRowCount(4)
tableWidget.setColumnCount(3)
tableWidget.setHorizontalHeaderLabels(['name', 'sex', 'weigh(kg)'])
newItem = QTableWidgetItem('小明') # 单元格的数据项
newItem.setFont(QFont('Times', 14, QFont.Black)) # 字体,字号,颜色
newItem.setForeground(QBrush(QColor(255, 0, 0)))
tableWidget.setItem(0, 0, newItem)
newItem = QTableWidgetItem('女')
newItem.setForeground(QBrush(QColor(255, 255, 0)))
newItem.setBackground(QBrush(QColor(0, 0, 255))) # rgb
tableWidget.setItem(0, 1, newItem)
newItem = QTableWidgetItem('100')
newItem.setFont(QFont('Times', 20, QFont.Black))
newItem.setForeground(QBrush(QColor(0, 0, 255)))
tableWidget.setItem(0, 2, newItem)
layout.addWidget(tableWidget)
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = CellFontAndColor()
main.show()
sys.exit(app.exec_())
按列排序
1.按哪一列排序
2.排序类型:升序或降序
sortItems( columnIndex,orderType)
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 23:23
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class CellFontAndColor(QWidget):
def __init__(self):
super(CellFontAndColor, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('设置单元格字体和颜色')
self.resize(540, 230)
layout = QHBoxLayout()
self.tableWidget = QTableWidget() # 表格对象
self.tableWidget.setRowCount(4)
self.tableWidget.setColumnCount(3)
self.tableWidget.setHorizontalHeaderLabels(['name', 'sex', 'weigh(kg)'])
# 添加数据
newItem = QTableWidgetItem('张三')
self.tableWidget.setItem(0, 0, newItem)
newItem = QTableWidgetItem('男')
self.tableWidget.setItem(0, 1, newItem)
newItem = QTableWidgetItem('165')
self.tableWidget.setItem(0, 2, newItem)
newItem = QTableWidgetItem('李四')
self.tableWidget.setItem(1, 0, newItem)
newItem = QTableWidgetItem('女')
self.tableWidget.setItem(1, 1, newItem)
newItem = QTableWidgetItem('120')
self.tableWidget.setItem(1, 2, newItem)
newItem = QTableWidgetItem('王五')
self.tableWidget.setItem(2, 0, newItem)
newItem = QTableWidgetItem('男')
self.tableWidget.setItem(2, 1, newItem)
newItem = QTableWidgetItem('130')
self.tableWidget.setItem(2, 2, newItem)
# 点击按钮排序
self.btn = QPushButton('升序')
self.btn.clicked.connect(self.order)
# 常量
self.orderType = Qt.DescendingOrder
layout.addWidget(self.tableWidget)
layout.addWidget(self.btn)
self.setLayout(layout)
# 升降序来回切换
def order(self):
if self.orderType == Qt.DescendingOrder:
self.orderType = Qt.AscendingOrder
self.btn.setText('降序') # 重命名按钮名,setText设置按钮显示文本
else:
self.orderType = Qt.DescendingOrder
self.btn.setText('升序')
# print(Qt.DescendingOrder)
# print(self.orderType)
self.tableWidget.sortItems(2, self.orderType) # 按照第三列的数据项排序
# self.tableWidget.sortItems(2, Qt.DescendingOrder)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = CellFontAndColor()
main.show()
sys.exit(app.exec_())
setTextAlignment
Qt. AlignRight 右对齐 Qt.AlignBottom底端显示
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 23:29
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class CellTextAlignment(QWidget):
def __init__(self):
super(CellTextAlignment, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('设置单元格的文本对齐方式')
self.resize(430, 230)
layout = QHBoxLayout()
# 表格对象
tableWidget = QTableWidget()
# 四行三列
tableWidget.setRowCount(4)
tableWidget.setColumnCount(3)
# 设置表格字段
tableWidget.setHorizontalHeaderLabels(['姓名', '性别', '体重(kg)'])
newItem = QTableWidgetItem('小明')
# 下面说的对齐与显示都是指在单元格中
# 右对齐 底端显示,即右下,Qt.AlignRight默认是右上
newItem.setTextAlignment(Qt.AlignRight | Qt.AlignBottom)
tableWidget.setItem(0, 0, newItem)
# 中心对齐,底部显示
newItem = QTableWidgetItem('男')
newItem.setTextAlignment(Qt.AlignCenter | Qt.AlignBottom)
tableWidget.setItem(0, 1, newItem)
newItem = QTableWidgetItem('190')
newItem.setTextAlignment(Qt.AlignRight)
tableWidget.setItem(0, 2, newItem)
layout.addWidget(tableWidget)
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = CellTextAlignment()
main.show()
sys.exit(app.exec_())
setSpan(row, col ,要合并的行数,要合并的列数)
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 23:31
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class MergeCell(QWidget):
def __init__(self):
super(MergeCell, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('合并单元格')
self.resize(430, 230)
layout = QHBoxLayout()
# 表格对象
tableWidget = QTableWidget()
# 四行三列
tableWidget.setRowCount(4)
tableWidget.setColumnCount(3)
# 设置表格字段
tableWidget.setHorizontalHeaderLabels(['姓名', '性别', '体重(kg)'])
newItem = QTableWidgetItem('小明')
tableWidget.setItem(0, 0, newItem)
# setSpan(row, col, 要合并的行数,要合并的列数)
tableWidget.setSpan(0, 0, 3, 1)
newItem = QTableWidgetItem('男')
tableWidget.setItem(0, 1, newItem)
tableWidget.setSpan(0, 1, 2, 1)
newItem = QTableWidgetItem('190')
tableWidget.setItem(0, 2, newItem)
newItem = QTableWidgetItem('test')
tableWidget.setItem(2, 1, newItem)
tableWidget.setSpan(2, 1, 1, 2)
layout.addWidget(tableWidget)
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = MergeCell()
main.show()
sys.exit(app.exec_())
单元格大小可手动拖动改变大小,当字体设置很大时,运行之后显示的单元格大小可能不足够显示出文字,只会显示三个点省略,这时就要设置单元格尺寸了。
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 23:34
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class MergeCell(QWidget):
def __init__(self):
super(MergeCell, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('合并单元格')
self.resize(600, 400)
layout = QHBoxLayout()
# 表格对象
tableWidget = QTableWidget()
# 四行三列
tableWidget.setRowCount(4)
tableWidget.setColumnCount(3)
# 设置表格字段
tableWidget.setHorizontalHeaderLabels(['姓名', '性别', '体重(kg)'])
newItem = QTableWidgetItem('小明') # 单元格的数据项
newItem.setFont(QFont('Times', 40, QFont.Black)) # 字体,字号,颜色
newItem.setForeground(QBrush(QColor(255, 0, 0)))
tableWidget.setItem(0, 0, newItem)
newItem = QTableWidgetItem('女')
newItem.setForeground(QBrush(QColor(255, 255, 0)))
newItem.setBackground(QBrush(QColor(0, 0, 255))) # rgb
tableWidget.setItem(0, 1, newItem)
newItem = QTableWidgetItem('100')
newItem.setFont(QFont('Times', 60, QFont.Black))
newItem.setForeground(QBrush(QColor(0, 0, 255)))
tableWidget.setItem(0, 2, newItem)
tableWidget.setRowHeight(0, 120) # 设置第一行高度,三个数据项都在第一行上,第一行的单元格高度都变为120
tableWidget.setColumnWidth(0, 150) # 设置第一列宽度
tableWidget.setRowHeight(2, 200) # 设置第三行高度,注意这是第三行,而不是第三个单元格的高度!!!!!
tableWidget.setColumnWidth(2, 180) # 设置第二列宽度
layout.addWidget(tableWidget)
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = MergeCell()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 23:38
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class MergeCell(QWidget):
def __init__(self):
super(MergeCell, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('合并单元格')
self.resize(600, 250)
layout = QHBoxLayout()
# 表格对象
tableWidget = QTableWidget()
# 四行四列
tableWidget.setRowCount(4)
tableWidget.setColumnCount(4)
# 设置表格字段
tableWidget.setHorizontalHeaderLabels(['姓名', '性别', '体重(kg)'])
newItem = QTableWidgetItem('李宁')
tableWidget.setItem(0, 0, newItem)
newItem = QTableWidgetItem('男')
tableWidget.setItem(0, 1, newItem)
newItem = QTableWidgetItem('160')
tableWidget.setItem(0, 2, newItem)
newItem = QTableWidgetItem(QIcon('./and.png'), '背包')
tableWidget.setItem(0, 3, newItem)
layout.addWidget(tableWidget)
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = MergeCell()
main.show()
sys.exit(app.exec_())
setIconSize(QSize(width, height))
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 23:44
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class CellImageSize(QWidget):
def __init__(self):
super(CellImageSize, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('改变单元格中图片尺寸')
self.resize(1000, 900)
layout = QHBoxLayout()
# 表格对象
tableWidget = QTableWidget()
# 设置单元格中图片大小
tableWidget.setIconSize(QSize(300, 200))
# 五行三列
tableWidget.setRowCount(5)
tableWidget.setColumnCount(3)
# 设置表格字段
tableWidget.setHorizontalHeaderLabels(['image1', 'image2', 'image3'])
# 让列的宽度和图片的宽度相同
for i in range(3):
tableWidget.setColumnWidth(i, 300)
# 让行的高度和图片的高度相同
for i in range(5):
tableWidget.setRowHeight(i, 200)
for k in range(15):
i = k / 3 # 行
j = k % 3 # 列
item = QTableWidgetItem()
item.setIcon(QIcon('./csdn/csdn%d.png' % (k + 1)))
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_())
1.如何弹出菜单
2.如果在满足条件的情况下弹出菜单
QMenu. exec_()
# @CSDN王家视频教程图书馆
# @Time 2022/11/23 23:56
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class CellImageSize(QWidget):
def __init__(self):
super(CellImageSize, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('在表格中显示上下文菜单')
self.resize(500, 200)
layout = QHBoxLayout()
# 表格对象
self.tableWidget = QTableWidget()
# 五行三列
self.tableWidget.setRowCount(4)
self.tableWidget.setColumnCount(3)
# 设置表格字段
self.tableWidget.setHorizontalHeaderLabels(['name', 'sex', 'weigh'])
# 添加数据
newItem = QTableWidgetItem('小明')
self.tableWidget.setItem(0, 0, newItem)
newItem = QTableWidgetItem('男')
self.tableWidget.setItem(0, 1, newItem)
newItem = QTableWidgetItem('190')
self.tableWidget.setItem(0, 2, newItem)
newItem = QTableWidgetItem('小亮')
self.tableWidget.setItem(1, 0, newItem)
newItem = QTableWidgetItem('男')
self.tableWidget.setItem(1, 1, newItem)
newItem = QTableWidgetItem('100')
self.tableWidget.setItem(1, 2, newItem)
newItem = QTableWidgetItem('小红')
self.tableWidget.setItem(2, 0, newItem)
newItem = QTableWidgetItem('女')
self.tableWidget.setItem(2, 1, newItem)
newItem = QTableWidgetItem('90')
self.tableWidget.setItem(2, 2, newItem)
# 设置允许弹出上下文你菜单
self.tableWidget.setContextMenuPolicy(Qt.CustomContextMenu)
# 信号与槽
self.tableWidget.customContextMenuRequested.connect(self.generateMenu)
layout.addWidget(self.tableWidget)
self.setLayout(layout)
def generateMenu(self, pos):
print('pos=', pos)
for i in self.tableWidget.selectionModel().selection().indexes():
rowNum = i.row()
print('选择了第%d行' % (rowNum + 1))
# 如果选择的行索引小于2,弹出上下文菜单
if rowNum < 2:
menu = QMenu()
item1 = menu.addAction('菜单项1') # 一个动作
# print(type(item1))
item2 = menu.addAction('菜单项2')
item3 = menu.addAction('菜单项3')
# pos是相对于整个屏幕的坐标,所以要转换为窗口坐标
screenPos = self.tableWidget.mapToGlobal(pos)
print('screenPos=', screenPos)
# 被阻塞
action = menu.exec_(screenPos)
if action == item1:
print('选择了第一个菜单项', self.tableWidget.item(rowNum, 0).text(),
self.tableWidget.item(rowNum, 1).text(),
self.tableWidget.item(rowNum, 2).text())
elif action == item2:
print('选择了第二个菜单项', self.tableWidget.item(rowNum, 0).text(),
self.tableWidget.item(rowNum, 1).text(),
self.tableWidget.item(rowNum, 2).text())
elif action == item3:
print('选择了第三个菜单项', 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 = CellImageSize()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 10:00
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class BasicTreeWidget(QMainWindow):
def __init__(self, parent=None):
super(BasicTreeWidget, self).__init__(parent)
self.setWindowTitle('树控件(QTreeWidget)的基本用法')
self.resize(500, 300)
# 树
self.tree = QTreeWidget()
# 为树控件指定列数
self.tree.setColumnCount(2)
# 指定列标签
self.tree.setHeaderLabels(['Key', 'Value'])
# 根节点
root = QTreeWidgetItem(self.tree)
root.setText(0, '根节点') # 0代表第一列,即Key列
root.setIcon(0, QIcon('./and.png')) # 为节点设置图标
self.tree.setColumnWidth(0, 200) # 第一列列宽设为200
# 添加子节点1
child1 = QTreeWidgetItem(root)
child1.setText(0, '子节点1') # 第一列Key为 子节点1
child1.setText(1, '子节点1的数据') # 第二列Value为 子节点1的数据
child1.setIcon(0, QIcon('./and.png'))
# 设置子节点1开启复选框状态
child1.setCheckState(0, Qt.Checked)
# 添加子节点2
child2 = QTreeWidgetItem(root)
child2.setText(0, '子节点2')
child2.setIcon(0, QIcon('./and.png'))
# 为child2添加一个子节点
child3 = QTreeWidgetItem(child2)
child3.setText(0, '子节点2-1')
child3.setText(1, '新的值')
child3.setIcon(0, QIcon('./and.png'))
# 默认所有节点都处于展开状态
self.tree.expandAll()
# 将树控件设为中心控件,即树控件会自动铺满整个屏幕
self.setCentralWidget(self.tree)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = BasicTreeWidget()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 10:08
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class TreeEvent(QMainWindow):
def __init__(self, parent=None):
super(TreeEvent, self).__init__(parent)
self.setWindowTitle('为树添加响应事件')
self.resize(400, 300)
# 树
self.tree = QTreeWidget()
# 为树控件指定列数
self.tree.setColumnCount(2)
# 指定列标签
self.tree.setHeaderLabels(['Key', 'Value'])
# 根节点
root = QTreeWidgetItem(self.tree)
root.setText(0, 'root') # 0代表第一列,即Key列,值为root
root.setText(1, '0')
# 添加子节点child1
child1 = QTreeWidgetItem(root)
child1.setText(0, 'child1')
child1.setText(1, '1')
# 添加子节点child2
child2 = QTreeWidgetItem(root)
child2.setText(0, 'child2')
child2.setText(1, '2')
# 为child2添加一个子节点child3
child3 = QTreeWidgetItem(child2)
child3.setText(0, 'child3')
child3.setText(1, '3')
# 信号和槽
self.tree.clicked.connect(self.onTreeClicked)
# 将树控件设为中心控件,即树控件会自动铺满整个屏幕
self.setCentralWidget(self.tree)
def onTreeClicked(self, index): # index是被点击节点的索引
item = self.tree.currentItem() # 获得当前单击项
print('当前处于第%d行' % index.row()) # 输出当前行(自己父节点的第几个值)
print('key=%s,value=%s' % (item.text(0), item.text(1)))
print()
if __name__ == '__main__':
app = QApplication(sys.argv)
main = TreeEvent()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 10:14
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class ModifyTree(QWidget):
def __init__(self, parent=None):
super(ModifyTree, self).__init__(parent)
self.setWindowTitle('增加修改和删除树控件中的节点')
self.resize(400, 300)
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.tree = QTreeWidget()
# 为树控件指定列数
self.tree.setColumnCount(2)
# 指定列标签
self.tree.setHeaderLabels(['Key', 'Value'])
# 根节点
root = QTreeWidgetItem(self.tree)
root.setText(0, 'root') # 0代表第一列,即Key列,值为root
root.setText(1, '0')
# 添加子节点child1
child1 = QTreeWidgetItem(root)
child1.setText(0, 'child1')
child1.setText(1, '1')
# 添加子节点child2
child2 = QTreeWidgetItem(root)
child2.setText(0, 'child2')
child2.setText(1, '2')
# 为child2添加一个子节点child3
child3 = QTreeWidgetItem(child2)
child3.setText(0, 'child3')
child3.setText(1, '3')
# 信号和槽
self.tree.clicked.connect(self.onTreeClicked)
mainLayout = QVBoxLayout(self)
mainLayout.addLayout(operatorLayout)
mainLayout.addWidget(self.tree)
self.setLayout(mainLayout)
def onTreeClicked(self, index): # index是被点击节点的索引
item = self.tree.currentItem() # 获得当前单击项
print('当前处于第%d行' % index.row()) # 输出当前行(自己父节点的第几个值)
print('key=%s,value=%s' % (item.text(0), item.text(1)))
print()
def addNode(self):
print('添加节点')
item = self.tree.currentItem() # 获得当前节点
print('当前节点是:', item)
node = QTreeWidgetItem(item)
node.setText(0, '新节点')
node.setText(1, '新值')
def updateNode(self):
print('修改节点')
item = self.tree.currentItem()
item.setText(0, '修改节点')
item.setText(1, '值已经被修改')
def deleteNode(self):
print('删除节点')
# 防止item是root时,root无父结点报错,要使用下面的写法
rootFather = self.tree.invisibleRootItem() # 获得根节点root的不可见的父节点
for item in self.tree.selectedItems():
# 父节点不为空
(item.parent() or rootFather).removeChild(item)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = ModifyTree()
main.show()
sys.exit(app.exec_())
一般复杂的树控件用QTreeView来写
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 10:21
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
if __name__ == '__main__':
app = QApplication(sys.argv)
# 显示目录结构的模型
model = QDirModel()
tree = QTreeView()
tree.setModel(model)
tree.setWindowTitle('QTreeView')
tree.resize(600, 400)
tree.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 10:25
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class TabWidget(QTabWidget): # 直接一整个屏幕就是一个选项卡窗口
def __init__(self, parent=None):
super(TabWidget, self).__init__(parent)
self.setWindowTitle('选项卡控件:QTabWidget')
self.resize(400, 200)
# 创建用于显示控件的窗口
self.tab1 = QWidget()
self.tab2 = QWidget()
self.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) # 别忘了tab1就是一个窗口
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)
main = TabWidget()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 10:30
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class StackedExample(QWidget): # 直接一整个屏幕就是一个选项卡窗口
def __init__(self, parent=None):
super(StackedExample, self).__init__(parent)
self.setWindowTitle('堆栈窗口控件:QStackedWidget')
# self.resize(400,200)
self.setGeometry(800, 450, 10, 10)
# 列表控件
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)
self.list.currentRowChanged.connect(self.display)
hbox = QHBoxLayout()
hbox.addWidget(self.list)
hbox.addWidget(self.stack)
self.setLayout(hbox)
def tab1UI(self):
# 表单布局
layout = QFormLayout()
layout.addRow('姓名', QLineEdit())
layout.addRow('地址', QLineEdit())
self.stack1.setLayout(layout) # 别忘了tab1就是一个窗口
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):
# 通过索引来切换页面
self.stack.setCurrentIndex(index)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = StackedExample()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 10:35
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class DockDemo(QMainWindow): # 直接一整个屏幕就是一个选项卡窗口
def __init__(self, parent=None):
super(DockDemo, self).__init__(parent)
self.setWindowTitle('停靠控件(QDockWidget)')
self.setGeometry(800, 450, 500, 500) # x,y,w,h
# self.resize(400, 200)
layout = QHBoxLayout()
# 停靠控件对象
self.items = QDockWidget('Dockable', self)
# 列表控件
self.listWidget = QListWidget()
self.listWidget.addItem('item1')
self.listWidget.addItem('item2')
self.listWidget.addItem('item3')
# 将列表放到停靠控件上
self.items.setWidget(self.listWidget)
self.setCentralWidget(QLineEdit('单行输入'))
# 设置一开始就是悬浮状态
self.items.setFloating(True)
# 在窗口上设置停靠控件,且悬浮在右侧
self.addDockWidget(Qt.RightDockWidgetArea, self.items)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = DockDemo()
main.show()
sys.exit(app.exec_())
相当于窗口的容器,里面可以有很多子窗口,但子窗口只能在这里面移动。
需要的类:
容纳多文档:QMdiArea
子窗口: QMdiSubWindow
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 10:44
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class MultiWindows(QMainWindow): # 直接一整个屏幕就是一个选项卡窗口
count = 0 # 记录当前有多少个菜单项
def __init__(self, parent=None):
super(MultiWindows, self).__init__(parent)
self.setWindowTitle('容纳多文档的窗口')
self.setGeometry(800, 450, 500, 400) # x,y,w,h
# 容纳多文档容器对象
self.mdi = QMdiArea()
bar = self.menuBar()
file = bar.addMenu('File')
file.addAction('New')
file.addAction('cascade') # 重叠
file.addAction('Tiled') # 平铺
file.triggered.connect(self.windowAction)
self.setCentralWidget(self.mdi)
def windowAction(self, q): # q是当前的单击菜单项,通过按钮名来进行不同的操作
if q.text() == 'New':
self.count = self.count + 1
# 子窗口对象
sub = QMdiSubWindow()
sub.setWidget(QTextEdit())
sub.setWindowTitle('子窗口' + str(self.count))
self.mdi.addSubWindow(sub)
sub.show()
# 下面两个是对mdi中已有的窗口排布进行操作,而不是生成窗口
elif q.text() == 'cascade':
self.mdi.cascadeSubWindows()
elif q.text() == 'Tiled':
self.mdi.tileSubWindows()
if __name__ == '__main__':
app = QApplication(sys.argv)
main = MultiWindows()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 10:52
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class ScrollBar(QWidget):
def __init__(self):
super(ScrollBar, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('滚动条控件演示')
self.setGeometry(400, 300, 300, 500)
# 水平布局
hbox = QHBoxLayout()
# 定义控件
self.label = QLabel('拖动滚动条去改变文字颜色')
self.scrollbar1 = QScrollBar() # 滚动条
self.scrollbar1.setMaximum(255) # 滚动条最大值
# 信号与槽
self.scrollbar1.sliderMoved.connect(self.sliderMoved)
self.scrollbar2 = QScrollBar()
self.scrollbar2.setMaximum(255)
self.scrollbar2.sliderMoved.connect(self.sliderMoved)
self.scrollbar3 = QScrollBar()
self.scrollbar3.setMaximum(255)
self.scrollbar3.sliderMoved.connect(self.sliderMoved)
self.scrollbar4 = QScrollBar()
self.scrollbar4.setMaximum(255)
self.scrollbar4.sliderMoved.connect(self.sliderMoved1)
# 向布局中添加控件
hbox.addWidget(self.label)
hbox.addWidget(self.scrollbar1)
hbox.addWidget(self.scrollbar2)
hbox.addWidget(self.scrollbar3)
hbox.addWidget(self.scrollbar4)
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)
# 参数一:QPalette.Foreground设置前景色,即标签的颜色 参数2:颜色
palette.setColor(QPalette.Foreground, c)
self.label.setPalette(palette)
def sliderMoved1(self):
# 向下移动标签
self.label.move(self.label.x(), self.y + self.scrollbar4.value())
if __name__ == '__main__':
app = QApplication(sys.argv)
main = ScrollBar()
main.show()
sys.exit(app.exec_())
QTimer定时器,适用于多任务,即每隔一定的时间会调用一次
QThread:完成单个任务可以使用这个
多线程:用于同时完成多个任务
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 10:57
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class showTime(QWidget):
def __init__(self, parent=None):
super(showTime, self).__init__(parent)
self.setWindowTitle('动态显示当前时间')
self.label = QLabel('显示当前时间')
self.startBtn = QPushButton('开始')
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()
# dddd是星期几
timeDispaly = time.toString('yyyy-MM-dd hh:mm:ss dddd')
# 将标签设置成当前时间
self.label.setText(timeDispaly)
def startTimer(self):
# 参数是时间间隔,1000毫秒
self.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)
main = showTime()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 11:05
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
if __name__ == '__main__':
app = QApplication(sys.argv)
label = QLabel('Hello World,窗口在5秒后自动关闭!')
# setWindowFlag设置窗口属性:启动画面,无框架
label.setWindowFlags(Qt.SplashScreen | Qt.FramelessWindowHint)
label.show()
# 5秒之后退出整个程序
QTimer.singleShot(5000, app.quit)
sys.exit(app.exec_())
用到自定义信号,之前用到的信号都是系统已经定义好的,这里需要自己再定义一个。
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 11:09
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
# 全局变量,当前计数从0开始
sec = 0
class WorkThread(QThread): # 继承QThread类
# 每隔一秒发送一次信号,pyqtSignal()用来定义信号的
timer = pyqtSignal()
# 计数完成后发送一次信号
end = pyqtSignal()
def run(self):
while True:
self.sleep(1) # 休眠一秒
if sec == 5:
self.end.emit() # 发送end信号,emit()用来发送信号
break
self.timer.emit() # 发送timer信号
class Counter(QWidget):
def __init__(self, parent=None):
super(Counter, self).__init__(parent)
self.setWindowTitle('使用线程类(QThread)编写计数器')
self.resize(300, 120)
layout = QVBoxLayout() # 垂直布局
# 数码管
self.lcdNumber = QLCDNumber()
layout.addWidget(self.lcdNumber)
btn = QPushButton('开始计数')
layout.addWidget(btn)
self.workThread = WorkThread()
self.workThread.timer.connect(self.countTime)
self.workThread.end.connect(self.end)
btn.clicked.connect(self.work)
self.setLayout(layout)
def countTime(self):
global sec # 声明一下是全局变量
sec += 1
self.lcdNumber.display(sec)
def end(self):
QMessageBox.information(self, '消息', '计数结束', QMessageBox.Ok)
def work(self):
self.workThread.start()
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Counter()
main.show()
sys.exit(app.exec_())
PyQt5和web的交互技术
同时使用Python和web开发程序,混合开发
Python+JavaScript+Html+CSS
运行报错问题:
from PyQt5.QtWebEngineWidgets import *
ImportError: DLL load failed while importing QtWebEngineWidgets: 找不到指定的模块。
参考:(已解决)from PyQt5.QtWebEngineWidgets import *:ImportError: DLL load failed / 找不到指定的模块_嗨嗨皮皮大bobo的博客-CSDN博客
CSDN和百度了很多
我的解决方案是:将python3.9版本改为3.6版本 想着还是python过高的原因
右键运行
test.html Html文件
测试页面
Hello PyQt5
Hello PyQt5
Hello PyQt5
Hello PyQt5
localHTML Py文件
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 12:52
import sys
import os
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class localHTML(QMainWindow):
def __init__(self, parent=None):
super(localHTML, self).__init__(parent)
self.setWindowTitle('装载本地Web页面')
self.setGeometry(5, 30, 1355, 730)
# os.getcwd()是获取当前路径
print(os.getcwd())
url = os.getcwd() + '/test.html'
self.browser = QWebEngineView()
# QUrl.fromLocalFile(url)
self.browser.load(QUrl.fromLocalFile(url))
self.setCentralWidget(self.browser)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = localHTML()
main.show()
sys.exit(app.exec_())
将web页面的代码硬编码到代码里面,然后显示
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 12:58
import sys
import os
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class innerHTML(QMainWindow):
def __init__(self, parent=None):
super(innerHTML, self).__init__(parent)
self.setWindowTitle('装载本地Web页面')
self.setGeometry(5, 30, 1355, 730)
self.browser = QWebEngineView()
# 直接嵌入页面源码
self.browser.setHtml('''
测试页面
Hello PyQt5
Hello PyQt5
Hello PyQt5
Hello PyQt5
''')
self.setCentralWidget(self.browser)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = innerHTML()
main.show()
sys.exit(app.exec_())
PyQt5和JavaScript交互
什么叫交互
PyQt5 <-> JavaScriptPyQt5调用JavaScript的函数,然后JavaScript的函数返回了值给PyQt5。
运行结果:功能:分别输入First name和Last name,然后 PyQt5调用JavaScript的函数,返回全名。
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 13:14
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtWebEngineWidgets import *
import sys
import os
class WebEngineView(QWidget):
"""
PyQt5调用JavaScript代码
PyQt5和JavaScrip交互
什么叫交互
PyQt5<->JavaScript 即互相调用内部的函数
"""
def __init__(self):
super(WebEngineView, self).__init__()
self.setWindowTitle('PyQt5调用JavaScript')
self.setGeometry(5, 30, 1355, 730)
self.layout = QVBoxLayout()
self.setLayout(self.layout)
self.browser = QWebEngineView()
url = os.getcwd() + '/pyqt5calljs.html'
self.browser.load(QUrl.fromLocalFile(url))
self.layout.addWidget(self.browser)
button = QPushButton('设置全名')
button.clicked.connect(self.fullname)
self.layout.addWidget(button)
# 接受js返回值 即pyqt5calljs.html文件中的fullname函数返回值
def js_callback(self, result):
print(result)
def fullname(self):
self.value = 'hello world'
self.browser.page().runJavaScript('fullname("' + self.value + '");', self.js_callback)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = WebEngineView()
print(main.__doc__)
main.show()
sys.exit(app.exec_())
阶乘小知识:
阶乘是基斯顿·卡曼(Christian Kramp,1760~1826)于 1808 年发明的运算符号,是数学术语。
一个正整数的阶乘(factorial)是所有小于及等于该数的正整数的积,并且0的阶乘为1。自然数n的阶乘写作n!。1808年,基斯顿·卡曼引进这个表示法。
阶乘指从1乘以2乘以3乘以4一直乘到所要求的数。
例如所要求的数是4,则阶乘式是1×2×3×4,得到的积是24,24就是4的阶乘。 例如所要求的数是6,则阶乘式是1×2×3×……×6,得到的积是720,720就是6的阶乘。例如所要求的数是n,则阶乘式是1×2×3×……×n,设得到的积是x,x就是n的阶乘。
将Python的一个对象映射到JavaScript中
将槽函数映射到JavaScript中总共有四个文件:
文件1 pyqt5calljs.html
文件2 js调用py文件(js_call_py.html)
文件3 阶乘功能类(factorial.py)
文件4 调用类(PyFactorial.py)
对应的pyqt5calljs.html文件如下:
qwebchannel.js
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, [email protected], author Milian Wolff
** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtWebChannel module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://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 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $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 directly
channel.send(data);
return;
}
if (channel.execId === Number.MAX_VALUE) {
// wrap
channel.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)
{
for (var i in message.data) {
var data = message.data[i];
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 (var objectName in data) {
var object = new QObject(objectName, data[objectName], channel);
}
// now unwrap properties, which might reference other registered objects
for (var objectName in 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 emission
this.__objectSignals__ = {};
// Cache of all properties, updated when a notify signal is emitted
this.__propertyCache__ = {};
var object = this;
// ----------------------------------------------------------------------
this.unwrapQObject = function(response)
{
if (response instanceof Array) {
// support list of objects
var ret = new Array(response.length);
for (var i = 0; i < response.length; ++i) {
ret[i] = object.unwrapQObject(response[i]);
}
return ret;
}
if (!response
|| !response["__QObject*__"]
|| response.id === undefined) {
return response;
}
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-40021
var propertyNames = [];
for (var propertyName in qObject) {
propertyNames.push(propertyName);
}
for (var idx in propertyNames) {
delete qObject[propertyNames[idx]];
}
}
});
// here we are already initialized, and thus must directly unwrap the properties
qObject.unwrapProperties();
return qObject;
}
this.unwrapProperties = function()
{
for (var propertyIdx in 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);
if (!isPropertyNotifySignal && signalName !== "destroyed") {
// only required for "pure" signals, handled separately for properties in propertyUpdate
// also note that we always get notified about the destroyed signal
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 propertyUpdate
webChannel.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 cache
for (var propertyIndex in propertyMap) {
var propertyValue = propertyMap[propertyIndex];
object.__propertyCache__[propertyIndex] = propertyValue;
}
for (var signalName in 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, signalArgs);
}
function addMethod(methodData)
{
var methodName = methodData[0];
var methodIdx = methodData[1];
object[methodName] = function() {
var args = [];
var callback;
for (var i = 0; i < arguments.length; ++i) {
if (typeof arguments[i] === "function")
callback = arguments[i];
else
args.push(arguments[i]);
}
webChannel.exec({
"type": QWebChannelMessageTypes.invokeMethod,
"object": object.__id__,
"method": methodIdx,
"args": args
}, function(response) {
if (response !== undefined) {
var result = object.unwrapQObject(response);
if (callback) {
(callback)(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 yet
object.__propertyCache__[propertyIndex] = propertyInfo[3];
if (notifySignalData) {
if (notifySignalData[0] === 1) {
// signal name is optimized away, reconstruct the actual name
notifySignalData[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 happen
console.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;
webChannel.exec({
"type": QWebChannelMessageTypes.setProperty,
"object": object.__id__,
"property": propertyIndex,
"value": value
});
}
});
}
// ----------------------------------------------------------------------
data.methods.forEach(addMethod);
data.properties.forEach(bindGetterSetter);
data.signals.forEach(function(signal) { addSignal(signal, false); });
for (var name in data.enums) {
object[name] = data.enums[name];
}
}
//required for use with nodejs
if (typeof module === 'object') {
module.exports = {
QWebChannel: QWebChannel
};
}
js调用py文件(js_call_py.html)
A Demo Page
阶乘功能类(factorial.py)
from PyQt5.QtCore import *
class Factorial(QObject):
@pyqtSlot(int, result=int)
def factorial(self,n):
if n == 0 or n == 1:
return 1
else:
return self.factorial(n - 1) * n
调用类(PyFactorial.py)
from PyQt5.QtWebChannel import QWebChannel
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import *
import sys
import os
from 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() + '/js_call_py.html'
#装载本地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)
win = PyFactorial()
win.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 14:29
import sys, math
from PyQt5.QtWidgets import *
class AbsoluteLayout(QWidget):
def __init__(self):
super(AbsoluteLayout, self).__init__()
self.setWindowTitle('绝对布局')
self.resize(300, 200)
self.label1 = QLabel('欢迎', self)
self.label1.move(15, 20)
self.label2 = QLabel('学习', self)
self.label2.move(35, 40)
self.label3 = QLabel('PyQt5', self)
self.label3.move(55, 60)
self.label4 = QLabel('JavaEE', self)
self.label4.move(75, 80)
self.label5 = QLabel('Uniapp', self)
self.label5.move(95, 100)
self.label6 = QLabel('大数据', self)
self.label6.move(115, 120)
self.label2 = QLabel('区块链', self)
self.label2.move(135, 140)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = AbsoluteLayout()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 14:34
import sys, math
from PyQt5.QtWidgets import *
class HBoxLayout(QWidget):
def __init__(self):
super(HBoxLayout, self).__init__()
self.setWindowTitle('水平盒布局')
self.resize(300, 200)
hlayout = QHBoxLayout()
hlayout.addWidget(QPushButton('JavaEE'))
hlayout.addWidget(QPushButton('Uniapp'))
hlayout.addWidget(QPushButton('大数据'))
hlayout.addWidget(QPushButton('区块链'))
hlayout.addWidget(QPushButton('人工智能'))
# 设置控件之间的间距
hlayout.setSpacing(20)
self.setLayout(hlayout)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = HBoxLayout()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 14:37
import sys, math
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class HBoxLayout(QWidget):
def __init__(self):
super(HBoxLayout, self).__init__()
self.setWindowTitle('水平盒布局')
self.resize(300, 200)
hlayout = QHBoxLayout()
'''
参数二:拉伸量(几个单位),eg:按钮1后面有2个单位的拉伸,按钮2后面有4个单位的拉伸
参数三:对齐方式,eg:按钮1是按照左上方对齐,其他以此类推
'''
hlayout.addWidget(QPushButton('按钮1'), 2, Qt.AlignLeft | Qt.AlignTop)
hlayout.addWidget(QPushButton('按钮2'), 4, Qt.AlignLeft | Qt.AlignTop)
hlayout.addWidget(QPushButton('按钮3'), 1, Qt.AlignLeft | Qt.AlignTop)
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)
main = HBoxLayout()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 14:42
import sys, math
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class VBoxLayout(QWidget):
def __init__(self):
super(VBoxLayout, self).__init__()
self.setWindowTitle('垂直盒布局')
self.resize(300, 200)
hlayout = QVBoxLayout()
hlayout.addWidget(QPushButton('JavaEE'))
hlayout.addWidget(QPushButton('Uniapp'))
hlayout.addWidget(QPushButton('大数据'))
hlayout.addWidget(QPushButton('区块链'))
hlayout.addWidget(QPushButton('人工智能'))
# 设置控件之间的间距
hlayout.setSpacing(40)
self.setLayout(hlayout)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = VBoxLayout()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 14:45
import sys, math
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class Stretch(QWidget):
def __init__(self):
super(Stretch, self).__init__()
self.setWindowTitle('设置伸缩量')
self.resize(800, 100)
btn1 = QPushButton(self)
btn2 = QPushButton(self)
btn3 = QPushButton(self)
btn1.setText('JavaEE')
btn2.setText('Uniapp')
btn3.setText('大数据')
layout = QHBoxLayout()
# 伸缩量,在水平布局里有讲过
layout.addStretch(1) # 在按钮前面添加伸缩单位
layout.addWidget(btn1)
layout.addStretch(2)
layout.addWidget(btn2)
layout.addStretch(3)
layout.addWidget(btn3)
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Stretch()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 14:47
import sys, math
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class Stretch(QWidget):
def __init__(self):
super(Stretch, self).__init__()
self.setWindowTitle('设置伸缩量')
self.resize(1000, 100)
btn1 = QPushButton(self)
btn2 = QPushButton(self)
btn3 = QPushButton(self)
btn4 = QPushButton(self)
btn5 = QPushButton(self)
btn1.setText('JavaEE')
btn2.setText('Uniapp')
btn3.setText('大数据')
btn4.setText('区块链')
btn5.setText('人工智能')
layout = QHBoxLayout()
layout.addStretch(0) # 伸缩量设置为0,是先排列
layout.addWidget(btn1)
layout.addWidget(btn2)
layout.addWidget(btn3)
layout.addWidget(btn4)
layout.addWidget(btn5)
btnOK = QPushButton(self)
btnOK.setText('确定')
btnCancel = QPushButton(self)
btnCancel.setText('取消')
layout.addStretch(1)
layout.addWidget(btnOK)
layout.addWidget(btnCancel)
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Stretch()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 14:50
import sys, math
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class RBBtn(QWidget):
def __init__(self):
super(RBBtn, self).__init__()
self.setWindowTitle('让按钮永远在右下角')
self.resize(400, 300)
okBtn = QPushButton('确定')
cancelBtn = QPushButton('取消')
hbox = QHBoxLayout()
hbox.addStretch(1)
hbox.addWidget(okBtn)
hbox.addWidget(cancelBtn)
vbox = QVBoxLayout()
btn1 = QPushButton('按钮1')
btn2 = QPushButton('按钮2')
btn3 = QPushButton('按钮3')
vbox.addStretch(0)
vbox.addWidget(btn1)
vbox.addWidget(btn2)
vbox.addWidget(btn3)
vbox.addStretch(1)
# 布局之间的叠加,用addLayout
vbox.addLayout(hbox)
self.setLayout(vbox)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = RBBtn()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 14:57
import sys, math
from PyQt5.QtWidgets import *
class Calc(QWidget):
def __init__(self):
super(Calc, self).__init__()
self.setWindowTitle('栅格布局:用循环方式实现计算器UI')
grid = QGridLayout()
self.setLayout(grid)
names = ['Cls', 'Back', '', 'Close',
'7', '8', '9', '/',
'4', '5', '6', '*',
'1', '2', '3', '-',
'0', '.', '=', '+']
positions = [(i, j) for i in range(5) for j in range(4)]
print(positions)#输出 按钮名称和坐标文职
# 在元组前面加星号可将元组变成两个单个的值
print(*(1, 2)) # 输出的不是元组,而是两个值
# zip函数返回一个可迭代的对象,接受多个可迭代的序列,将相应的元素组合成一对元组
for position, name in zip(positions, names):
if name == '':
continue
# print(position)
# print(name)
btn = QPushButton(name)
grid.addWidget(btn, *position)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Calc()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 15:09
import sys, math
from PyQt5.QtWidgets import *
class GridForm(QWidget):
def __init__(self):
super(GridForm, self).__init__()
self.setWindowTitle('栅格布局:进行表单UI设计')
# 标签
titleLabel = QLabel('标题')
authorLabel = QLabel('作者')
contentLabel = QLabel('内容')
# 单行输入
titleEdit = QLineEdit()
authorEdit = QLineEdit()
# 多行输入
contentEdit = QTextEdit()
grid = QGridLayout()
# 控件间距
grid.setSpacing(10)
grid.addWidget(titleLabel, 1, 0) # 位置两个轴都是从0开始,这里没用而已
grid.addWidget(titleEdit, 1, 1)
grid.addWidget(authorLabel, 2, 0)
grid.addWidget(authorEdit, 2, 1)
grid.addWidget(contentLabel, 3, 0)
grid.addWidget(contentEdit, 3, 1, 5, 1) # 空间上占五行一列
self.setLayout(grid)
self.resize(400, 300)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = GridForm()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 15:15
import sys, math
from PyQt5.QtWidgets import *
class FormLayout(QWidget):
def __init__(self):
super(FormLayout, self).__init__()
self.setWindowTitle('表单布局')
self.resize(350, 300)
# 标签
titleLabel = QLabel('标题')
authorLabel = QLabel('作者')
contentLabel = QLabel('内容')
# 单行输入
titleEdit = QLineEdit()
authorEdit = QLineEdit()
# 多行输入
contentEdit = QTextEdit()
formLayout = QFormLayout()
formLayout.addRow(titleLabel, titleEdit)
formLayout.addRow(authorLabel, authorEdit)
formLayout.addRow(contentLabel, contentEdit)
self.setLayout(formLayout)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = FormLayout()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 15:16
import sys, math
from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qt
class Splitter(QWidget):
def __init__(self):
super(Splitter, self).__init__()
self.setWindowTitle('Splitter例子')
self.setGeometry(400, 300, 300, 200)
topLeft = QFrame()
topLeft.setFrameShape(QFrame.StyledPanel) # 面板类型
bottom = QFrame()
bottom.setFrameShape(QFrame.StyledPanel)
splitter1 = QSplitter(Qt.Horizontal) # 水平拖动
textEdit = QTextEdit()
splitter1.addWidget(topLeft)
splitter1.addWidget(textEdit)
# 设置里面的控件的初始尺寸,eg:topLeft占100,textEdit占200
splitter1.setSizes([100, 200])
splitter2 = QSplitter(Qt.Vertical) # 垂直拖动
splitter2.addWidget(splitter1)
splitter2.addWidget(bottom)
hbox = QHBoxLayout()
hbox.addWidget(splitter2)
self.setLayout(hbox)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Splitter()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 15:24
import sys, math
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class Demo(QWidget):
def __init__(self):
super(Demo, self).__init__()
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 300, 100)
self.setWindowTitle('信号(Signal)与槽(Slot)')
self.btn = QPushButton('我的按钮', self)
self.btn.clicked.connect(self.onClick)
def onClick(self):
self.btn.setText('信号已经发出')
self.btn.setStyleSheet('QPushButton(max-width:500px;min-width:500px)')
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Demo()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 15:30
import sys, math
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class MyTypeSignal(QObject):
# 定义一个信号
sendmsg = pyqtSignal(object)
# 调用run来实现触发
def run(self):
self.sendmsg.emit('Hello PyQt5') # 给槽传递一个参数
class MySlot(QObject):
# 槽函数
def get(self, msg):
print('信息:' + msg)
if __name__ == '__main__':
send = MyTypeSignal()
slot = MySlot()
send.sendmsg.connect(slot.get) # 连接信号与槽函数
send.run() # 发送信号
# 断开信号与槽的连接
# send.sendmsg.disconnect(slot.get)
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 15:38
import sys, math
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class MyTypeSignal(QObject):
# 定义一个信号
sendmsg = pyqtSignal(object)
# 发送三个参数的信号
sendmsg1 = pyqtSignal(str, int, int)
# 调用run来实现触发
def run(self):
self.sendmsg.emit('Hello PyQt5') # 给槽传递一个参数
def run1(self):
self.sendmsg1.emit('hello', 3, 4)
class MySlot(QObject):
# 槽函数
def get(self, msg):
print('信息:' + msg)
def get1(self, msg, a, b):
print(msg)
print(a + b)
if __name__ == '__main__':
send = MyTypeSignal()
slot = MySlot()
send.sendmsg.connect(slot.get) # 连接信号与槽函数
send.sendmsg1.connect(slot.get1)
send.run() # 发送信号
send.run1() # 别忘了调用相应的触发函数!!!!
# 断开信号与槽的连接
# send.sendmsg.disconnect(slot.get)
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 15:43
import sys, math
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class MultiSignal(QObject):
# 无参数
signal1 = pyqtSignal()
# 有一个整型的参数
signal2 = pyqtSignal(int)
# 参数一是整型,参数二是字符型
signal3 = pyqtSignal(int, str)
# 参数是一个列表
signal4 = pyqtSignal(list)
# 参数是一个字典
signal5 = pyqtSignal(dict)
# 声明一个重载版本的信号,中括号之间是或的意思,也就是槽函数可以是两个参数:int和str类型,也可以是一个参数:str类型
signal6 = pyqtSignal([int, str], [str])
def __init__(self):
super(MultiSignal, self).__init__()
self.signal1.connect(self.signalcall1)
self.signal2.connect(self.signalcall2)
self.signal3.connect(self.signalcall3)
self.signal4.connect(self.signalcall4)
self.signal5.connect(self.signalcall5)
# self.signal6.connect(self.signalcall6)#默认关联到重构的第一个槽函数上
# 为了可读性,可像下面那样写
self.signal6[str].connect(self.signalcall6Overload)
self.signal6[int, str].connect(self.signalcall6)
self.signal1.emit()
self.signal2.emit(10)
self.signal3.emit(1, 'hello world')
self.signal4.emit([1, 2, 3, 4, 5])
self.signal5.emit({'name': 'Bill', 'age': 30})
self.signal6[str].emit('test')
self.signal6[int, str].emit(20, 'mytest')
# 槽函数
def signalcall1(self):
print('signal1 emit')
def signalcall2(self, val):
print('signa2 emit,value:', val)
def signalcall3(self, val, text):
print('signa3 emit,value:', val, text)
def signalcall4(self, val):
print('signa4 emit,value:', val)
def signalcall5(self, val):
print('signa5 emit,value:', val)
def signalcall6(self, val, text):
print('signa6 emit,value:', val, text)
def signalcall6Overload(self, val):
print('signa6 overload emit,value:', val)
if __name__ == '__main__':
multiSignal = MultiSignal()
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 15:54
import sys, math
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class NNSignal(QObject):
signal1 = pyqtSignal() # 无参数
signal2 = pyqtSignal(int)
signal3 = pyqtSignal()
def __init__(self):
super(NNSignal, self).__init__()
# 一个信号对应多个槽
self.signal1.connect(self.call1)
self.signal1.connect(self.call11)
self.signal1.emit()
# 信号绑定到槽上
self.signal2.connect(self.signal1)
print('*****************************')
self.signal2.emit(2) # 触发了信号1
'''
以上操作的运行结果
call1 emit
call11 emit
call1 emit
call11 emit
'''
print('************************************')
# 解绑
self.signal1.disconnect(self.call1)
self.signal1.disconnect(self.call11)
self.signal2.disconnect(self.signal1)
# 重新绑定
self.signal1.connect(self.call1)
self.signal2.connect(self.call2)
# 一个槽函数绑定到多个信号上
self.signal3.connect(self.call1)
self.signal1.emit()
self.signal2.emit(100)
self.signal3.emit()
def call1(self):
print('call1 emit')
def call11(self):
print('call11 emit')
def call2(self, val):
print('call2 emit', val)
if __name__ == '__main__':
nnSignal = NNSignal()
本质就是为一个类添加信号,只不过这个类是窗口类
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 16:02
import sys, math
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class WinSignal(QWidget):
# 定义一个信号
btn_clicked_signal = pyqtSignal()
def __init__(self):
super(WinSignal, self).__init__()
self.setWindowTitle('为窗口添加信号')
self.resize(300, 100)
btn = QPushButton('关闭窗口', self)
btn.clicked.connect(self.btn_clicked)
self.btn_clicked_signal.connect(self.btn_close)
# 起触发函数作用的槽函数
def btn_clicked(self):
self.btn_clicked_signal.emit()
# 关闭窗口作用的槽函数
def btn_close(self):
self.close()
if __name__ == '__main__':
app = QApplication(sys.argv)
main = WinSignal()
main.show()
sys.exit(app.exec_())
多线程更新UI数据,两个线程中传递数据
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 16:09
import sys, math
import time
from PyQt5.QtWidgets import QApplication, QDialog, QLineEdit
from PyQt5.QtCore import QThread, pyqtSignal, QDateTime
class BackendThread(QThread):
# 更新日期的信号
update_date = pyqtSignal(str)
def run(self):
while True:
date = QDateTime.currentDateTime()
currentTime = date.toString('yyyy-MM-dd hh:mm:ss')
# 信号参数是当前时间
self.update_date.emit(str(currentTime))
time.sleep(1) # 隔1s就发送一次信号
class ThreadUpdateUI(QDialog):
def __init__(self):
QDialog.__init__(self)
self.setWindowTitle('多线程更新UI数据')
self.resize(400, 100)
# 存放当前时间
self.input = QLineEdit(self)
self.input.resize(400, 100)
self.initUI()
def initUI(self):
self.backend = BackendThread()
self.backend.update_date.connect(self.handleDisplay)
self.backend.start() # 开启线程,自动调用run
# 槽函数是主线程
def handleDisplay(self, data): # data是当前时间
self.input.setText(data)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = ThreadUpdateUI()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 16:22
from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QPushButton
import sys
class AutoSignalSlot(QWidget):
def __init__(self):
super(AutoSignalSlot, self).__init__()
self.resize(300, 100)
self.okBtn = QPushButton('ok', self)
self.okBtn1 = QPushButton('cancel', self)
# 设置自动连接
self.okBtn.setObjectName('okBtn')
self.okBtn1.setObjectName('cancelBtn')
QtCore.QMetaObject.connectSlotsByName(self)
layout = QHBoxLayout()
layout.addWidget(self.okBtn)
layout.addWidget(self.okBtn1)
self.setLayout(layout)
# 传统连接信号与槽
# self.okBtn.clicked.connect(self.on_okBtn_clicked)
# 命名规则:on_发送者对象(objectname)名称_发射信号名称(self,参数)
@QtCore.pyqtSlot() # 标注为槽函数,以供自动连接使用
def on_okBtn_clicked(self):
print('点击了ok按钮')
@QtCore.pyqtSlot()
def on_cancelBtn_clicked(self):
print('点击了cancel按钮')
if __name__ == '__main__':
app = QApplication(sys.argv)
main = AutoSignalSlot()
main.show()
sys.exit(app.exec_())
Lambda表达式:匿名函数,也就是没有名字的函数。
将Lambda赋给一个变量,这个变量就成为了一个函数引用。或者将Lambda表达式作为一个参数传入函数。
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 16:32
# Lambda表达式示例
fun = lambda: print('hello world')
fun()
fun = lambda x, y: print(x, y)
fun('a', 'b')
from PyQt5.QtWidgets import *
import sys
class LambdaSlotArg(QMainWindow):
def __init__(self):
super(LambdaSlotArg, self).__init__()
self.setWindowTitle('用Lambda表达式为槽函数传递参数')
btn1 = QPushButton('按钮1')
btn2 = QPushButton('按钮2')
ok = 200
btn1.clicked.connect(lambda: self.onButtonClick(10, ok))
btn2.clicked.connect(lambda: self.onButtonClick(ok, -20))
btn1.clicked.connect(lambda: QMessageBox.information(self, '结果', '单击了btn1'))
layout = QHBoxLayout()
layout.addWidget(btn1)
layout.addWidget(btn2)
mainFrame = QWidget()
mainFrame.setLayout(layout)
self.setCentralWidget(mainFrame)
def onButtonClick(self, m, n):
print('m+n=', m + n)
QMessageBox.information(self, '结果', str(m + n))
if __name__ == '__main__':
app = QApplication(sys.argv)
main = LambdaSlotArg()
main.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 16:43
from PyQt5.QtWidgets import *
from functools import partial
import sys
class PartialSlotArg(QMainWindow):
def __init__(self):
super(PartialSlotArg, self).__init__()
self.setWindowTitle('用partial对象为槽函数传递参数')
btn1 = QPushButton('按钮1')
btn2 = QPushButton('按钮2')
x = 20
y = -123
btn1.clicked.connect(partial(self.onButtonClick, 10, 20))
btn2.clicked.connect(partial(self.onButtonClick, x, y))
layout = QHBoxLayout()
layout.addWidget(btn1)
layout.addWidget(btn2)
mainFrame = QWidget()
mainFrame.setLayout(layout)
self.setCentralWidget(mainFrame)
def onButtonClick(self, m, n):
print('m+n=', m + n)
QMessageBox.information(self, '结果', str(m + n))
if __name__ == '__main__':
app = QApplication(sys.argv)
main = PartialSlotArg()
main.show()
sys.exit(app.exec_())
系统已经定义了很多槽函数,我们能可以覆盖重写这些槽函数
我们通过覆盖keyPressEvent槽函数修改了按ESC和ALT键的行为。当我们按ESC的时候,窗口关闭,当按ALT键的时候窗口标题修改为"按下了Alt键"。
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 16:49
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import sys
class OverrideSlot(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('override(覆盖)槽函数')
# 键盘按下的槽函数,不需要连接,系统已经给连接了
def keyPressEvent(self, e):
# 如果按下Esc键,则关闭窗口
if e.key() == Qt.Key_Escape:
self.close()
# 如果按下Alt键,修改窗口标题为 按下Alt键
elif e.key() == Qt.Key_Alt:
self.setWindowTitle('按下Alt键')
if __name__ == '__main__':
app = QApplication(sys.argv)
main = OverrideSlot()
main.show()
sys.exit(app.exec_())
所谓的交互就是数据的传递。不使用信号与槽就是强耦合的方式,即两个窗口之间相互调用控件。
DateDialog.py
# @CSDN王家视频教程图书馆 # @Time 2022/11/24 16:55 from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * class DateDialog(QDialog): def __init__(self, parent=None): super(DateDialog, self).__init__(parent) # 当这里面传入self,相当于 self.setLayout(layout),而且上面的parent必须有 layout = QVBoxLayout(self) ''' QDateTimeEdit是一个允许用户编辑日期时间的控件,可以使用键盘上的上下键头按钮来增加或减少日期的时间值, QDateTimeEdit通过setDisplayFormat()函数来设置显示的日期时间格式 ''' # 日期时间输入框 self.datetime = QDateTimeEdit(self) # print(isinstance(datetime,DateDialog)) # popup (n.) 弹出;弹跳装置;发射 self.datetime.setCalendarPopup(True) # 显示当前日期 self.datetime.setDateTime(QDateTime.currentDateTime()) layout.addWidget(self.datetime) # 两个按钮 buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) # 下面两个槽函数是系统已经定义好的 buttons.accepted.connect(self.accept) # reject (v.)拒绝 buttons.rejected.connect(self.reject) layout.addWidget(buttons) def dateTime(self): # 返回当前日期 return self.datetime.dateTime() @staticmethod # 静态方法 def getDateTime(parent=None): dialog = DateDialog(parent) # 显示对话框 result = dialog.exec_() date = dialog.dateTime() # print('date.date():',date.date()) #日期:年月日 # print('date.time():',date.time())#时间:时分秒 # 第三个参数是:是否点击了ok return (date.date(), date.time(), result == QDialog.Accepted)
MutilWindow1.py
# @CSDN王家视频教程图书馆 # @Time 2022/11/24 16:57 import sys from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * from DateDialog import DateDialog class MutilWindow1(QWidget): def __init__(self): super(MutilWindow1, self).__init__() self.setWindowTitle('多窗口交互(1):不使用信号与槽') # 单行输入 self.lineEdit = QLineEdit(self) self.btn1 = QPushButton('弹出对话框1') self.btn1.clicked.connect(self.onButton1Click) self.btn2 = QPushButton('弹出对话框2') self.btn2.clicked.connect(self.onButton2Click) # 栅格布局 gridLayout = QGridLayout() gridLayout.addWidget(self.lineEdit) gridLayout.addWidget(self.btn1) gridLayout.addWidget(self.btn2) self.setLayout(gridLayout) def onButton1Click(self): dialog = DateDialog(self) result = dialog.exec_() date = dialog.dateTime() self.lineEdit.setText(date.date().toString()) # 销毁窗口 dialog.destroy() def onButton2Click(self): date, time, result = DateDialog.getDateTime() self.lineEdit.setText(date.toString()) if result == QDialog.Accepted: print('点击确定按钮') else: print('点击取消按钮') if __name__ == '__main__': app = QApplication(sys.argv) main = MutilWindow1() main.show() sys.exit(app.exec_())
低耦合:
如果一个窗口A与另一个窗口B交互,那么A尽量不要直接访问B窗口中的控件,
应该在窗口A中访问B窗口中的信号,并指定与信号绑定的槽函数例:如果A直接访问B窗口的控件,一旦B窗口控件发生改变,那么A和B的代码都需要变化
如果A访问的是B中的信号,那么B中的控件发生了改变,只需要修改B中的代码即可。信号就是为此而生
NewDateDialog.py# @CSDN王家视频教程图书馆 # @Time 2022/11/24 17:40 from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * class NewDateDialog(QDialog): # 定义一个信号,有一个字符串型的参数 Signal_OneParameter = pyqtSignal(str) def __init__(self, parent=None): super(NewDateDialog, self).__init__(parent) self.setWindowTitle('子窗口:用来发射信号') # 在布局中添加部件,垂直布局 layout = QVBoxLayout(self) self.label = QLabel(self) self.label.setText('前者发射内置信号\n后者发射自定义信号') # 定义两个日期时间编辑框 self.datetime_inner = QDateTimeEdit(self) # 弹出模式 self.datetime_inner.setCalendarPopup(True) # 设置为当前时间 self.datetime_inner.setDateTime(QDateTime.currentDateTime()) self.datetime_emit = QDateTimeEdit(self) self.datetime_emit.setCalendarPopup(True) self.datetime_emit.setDateTime(QDateTime.currentDateTime()) # 放入垂直布局 layout.addWidget(self.label) layout.addWidget(self.datetime_inner) layout.addWidget(self.datetime_emit) # 使用两个button(ok和cancel)分别连接accept()和reject()槽函数 buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) buttons.accepted.connect(self.accept) buttons.rejected.connect(self.reject) layout.addWidget(buttons) self.datetime_emit.dateTimeChanged.connect(self.emit_signal) def emit_signal(self): date_str = self.datetime_emit.dateTime().toString() print(date_str) # 发出信号 self.Signal_OneParameter.emit(date_str)
MutilWindow2.py# @CSDN王家视频教程图书馆 # @Time 2022/11/24 17:40 import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import * from NewDateDialog import NewDateDialog class MultiWindow2(QWidget): def __init__(self, parent=None): super(MultiWindow2, self).__init__(parent) self.resize(400, 90) self.setWindowTitle('多窗口交互(2):使用信号与槽') self.open_btn = QPushButton('获取时间') self.lineEdit_inner = QLineEdit(self) self.lineEdit_emit = QLineEdit(self) self.open_btn.clicked.connect(self.openDialog) self.lineEdit_inner.setText('接收子窗口内置信号的时间') self.lineEdit_emit.setText('接收子窗口自定义信号的时间') grid = QGridLayout() grid.addWidget(self.lineEdit_inner) grid.addWidget(self.lineEdit_emit) grid.addWidget(self.open_btn) self.setLayout(grid) def openDialog(self): dialog = NewDateDialog(self) # dateTimeChanged 是时间改变信号,即手动使日期时间发生改变就会发出信号 # 连接子窗口的内置信号与主窗口的槽函数 dialog.datetime_inner.dateTimeChanged.connect(self.deal_inner_slot) # 连接子窗口的自定义信号与主窗口的槽函数(推荐用这种) dialog.Signal_OneParameter.connect(self.deal_emit_slot) dialog.show() def deal_inner_slot(self, date): self.lineEdit_inner.setText(date.toString()) def deal_emit_slot(self, dateStr): self.lineEdit_emit.setText(dateStr) if __name__ == "__main__": app = QApplication(sys.argv) form = MultiWindow2() form.show() sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 18:13
import sys
from PyQt5.QtWidgets import *
from PyQt5 import QtCore
# 窗口可以显示的风格样式
print('窗口可以显示的风格样式:', QStyleFactory.keys())
class WindowStyle(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('设置窗口风格')
horizontalLayout = QHBoxLayout()
self.styleLabel = QLabel('设置窗口风格:')
# 下拉框
self.styleComboBox = QComboBox()
self.styleComboBox.addItems(QStyleFactory.keys())
# 获取当前窗口的风格
print('当前窗口的风格:', QApplication.style().objectName())
# 获取当前窗口的风格的索引
index = self.styleComboBox.findText(QApplication.style().objectName(), QtCore.Qt.MatchFixedString)
# 将下拉框初始设置为当前窗口的风格的名字
self.styleComboBox.setCurrentIndex(index)
self.styleComboBox.activated[str].connect(self.handleStyleChanged)
horizontalLayout.addWidget(self.styleLabel)
horizontalLayout.addWidget(self.styleComboBox)
self.setLayout(horizontalLayout)
def handleStyleChanged(self, style):
# 设置风格
QApplication.setStyle(style)
if __name__ == "__main__":
app = QApplication(sys.argv)
form = WindowStyle()
form.show()
sys.exit(app.exec_())
setWindowFlags ( WindowFlags type )
FrameWindowHint 没有边框的窗口
WindowStaysOnTopHint 总在最上面的窗口
CustomizeWindowHint 自定义窗口标题栏,以下标志必须与这个标志一起使用才有效,否则窗口将有默认的标题栏
WindowTitleHint 显示窗口标题栏
WindowSystemMenuHint 显示系统菜单
WindowMinimizeButtonHint 显示最小化按钮
WindowMaximizeButtonHint 显示最大化按钮
WindowMinMaxButtonsHint 显示最小化按钮和最大化按钮
WindowCloseButtonHint 显示关闭按钮
setWindowFlags(FramelessWindowHint) 直接隐藏掉
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 18:43
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
### 自定义窗口类
class WindowMaxMin(QWidget):
# 构造函数
def __init__(self, parent=None):
'''构造函数'''
# 调用父类构造函数
super(WindowMaxMin, self).__init__(parent)
self.resize(300, 400)
self.setWindowTitle("用代码控制窗口的最大化和最小化")
self.setWindowFlags(Qt.WindowMaximizeButtonHint | Qt.WindowCloseButtonHint | Qt.WindowMinMaxButtonsHint)
layout = QVBoxLayout()
maxButton1 = QPushButton()
maxButton1.setText('窗口最大化1 使用自己的方法')
maxButton1.clicked.connect(self.maximized1)
maxButton2 = QPushButton()
maxButton2.setText('窗口最大化2 使用系统提供的方法')
maxButton2.clicked.connect(self.showMaximized)
minButton = QPushButton()
minButton.setText('窗口最小化')
minButton.clicked.connect(self.showMinimized)
layout.addWidget(maxButton1)
layout.addWidget(maxButton2)
layout.addWidget(minButton)
self.setLayout(layout)
def maximized1(self):
# 获得桌面
desktop = QApplication.desktop()
# 获取桌面可用尺寸
rect = desktop.availableGeometry()
self.setGeometry(rect)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = WindowMaxMin()
window.show()
# 应用程序事件循环
sys.exit(app.exec_())
需要解决3个核心内容
1. 如何绘图在paintEvent方法中绘图,通过调用update方法触发painEvent的调用
2. 在哪里绘图
在白色背景的QPixmap对象中绘图
3. 如何通过移动鼠标进行绘图
鼠标拥有3个事件:
(1)鼠标按下:mousePressEvent
(2)鼠标移动:mouseMoveEvent
(3)鼠标抬起:mouseReleaseEvent
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 18:57
import sys
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtGui import QPainter, QPixmap
from PyQt5.QtCore import Qt, QPoint
class Drawing(QWidget):
def __init__(self, parent=None):
super(Drawing, self).__init__(parent)
self.setWindowTitle("绘图应用")
self.pix = QPixmap()
self.lastPoint = QPoint()
self.endPoint = QPoint()
self.initUi()
def initUi(self):
self.resize(600, 600)
'''
QPixmap 类用于绘图设备的图像显示,可作为一个 QPaintDevice 对象,也可以加载到一个控件中。
QPixmap 可以读取的图像文件类型有:BMP、GIF、JPG、JPEG、PNG、PBM、PGM、PPM、XBM、XPM 等。
'''
# 画布大小为600*600,背景为白色
self.pix = QPixmap(600, 600)
self.pix.fill(Qt.white)
# 下面的方法都是自动调用的
def paintEvent(self, event):
# 画笔
pp = QPainter(self.pix)
# 根据鼠标指针前后两个位置绘制直线
pp.drawLine(self.lastPoint, self.endPoint)
# 让前一个坐标值等于后一个坐标值,
# 这样就能实现画出连续的线
self.lastPoint = self.endPoint
painter = QPainter(self)
# pixmap (n.)像素映射,象图
# 即先画在QPixmap上,再从图像文件中提取 Pixmap 并将其显示在指定位置
painter.drawPixmap(0, 0, self.pix)
# 鼠标按下
def mousePressEvent(self, event):
# 如果鼠标左键按下
if event.button() == Qt.LeftButton:
# 获得当前坐标
self.lastPoint = event.pos()
# 鼠标移动
def mouseMoveEvent(self, event):
# 如果鼠标左键一直按着
if event.buttons() and Qt.LeftButton:
self.endPoint = event.pos()
self.update() # 触发paintEvent
# 鼠标抬起
def mouseReleaseEvent(self, event):
# 鼠标左键释放
if event.button() == Qt.LeftButton:
self.endPoint = event.pos()
# 进行重新绘制
self.update() # 每次调用paintEvent都会重新触发一次
if __name__ == "__main__":
app = QApplication(sys.argv)
form = Drawing()
form.show()
sys.exit(app.exec_())
QSS (Qt Style Sheets)
Qt样式表
用于设置控件的样式
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 19:37
from PyQt5.QtWidgets import *
import sys
class BasicQSS(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("QSS样式")
btn1 = QPushButton(self)
btn1.setText("按钮1")
btn2 = QPushButton(self)
btn2.setText("按钮2")
btn3 = QPushButton(self)
btn3.setText("按钮3")
vbox = QVBoxLayout()
vbox.addWidget(btn1)
vbox.addWidget(btn2)
vbox.addWidget(btn3)
self.setLayout(vbox)
if __name__ == "__main__":
app = QApplication(sys.argv)
form = BasicQSS()
# 选择器
# 所有的QPushButton控件都设置为背景颜色为红色
qssStyle = '''
QPushButton {
background-color:red
}
'''
form.setStyleSheet(qssStyle)
form.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 19:41
from PyQt5.QtWidgets import *
import sys
class QSSSelector(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("QSS样式")
btn1 = QPushButton(self)
btn1.setText("按钮1")
btn2 = QPushButton(self)
# 设置name属性,可根据属性来指定按钮
btn2.setProperty('name', 'btn2')
btn2.setText("按钮2")
btn3 = QPushButton(self)
btn3.setProperty('name', 'btn3')
btn3.setText("按钮3")
vbox = QVBoxLayout()
vbox.addWidget(btn1)
vbox.addWidget(btn2)
vbox.addWidget(btn3)
self.setLayout(vbox)
if __name__ == "__main__":
app = QApplication(sys.argv)
form = QSSSelector()
# 选择器
# 指定按钮
qssStyle = '''
QPushButton[name="btn2"] {
background-color:red;
color:yellow;
height:120;
font-size:60px;
}
QPushButton[name="btn3"] {
background-color:blue;
color:yellow;
height:60;
font-size:30px;
}
'''
form.setStyleSheet(qssStyle)
form.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 19:46
from PyQt5.QtWidgets import *
import sys
class QSSSubControl(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("QSS子控件选择器")
combo = QComboBox(self)
# 设置下拉框名字
combo.setObjectName("myComboBox")
combo.addItem("Window")
combo.addItem("Linux")
combo.addItem("Mac OS X")
combo.move(50, 50)
# 窗口的尺寸和位置
self.setGeometry(250, 200, 320, 150)
if __name__ == "__main__":
app = QApplication(sys.argv)
form = QSSSubControl()
'''
通过名字来引用,#myComboBox相当于web里通过id来引用
drop-down是下拉子控件
'''
qssStyle = '''
QComboBox#myComboBox::drop-down {
image:url(./csdnlogo.jpg)
}
'''
form.setStyleSheet(qssStyle)
form.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 19:54
from PyQt5.QtWidgets import *
import sys
class LabelButtonBackground(QWidget):
def __init__(self):
super().__init__()
label1 = QLabel(self)
# 鼠标放在上面就提示
label1.setToolTip('这是一个文本标签')
# QSS方式在label1上设置背景图
label1.setStyleSheet('QLabel{border-image:url(./csdnlogo.jpg);}')
label1.setFixedWidth(476)
label1.setFixedHeight(259)
btn1 = QPushButton(self)
btn1.setObjectName('btn1')
btn1.setMaximumSize(60, 60)
btn1.setMinimumSize(60, 60)
# 正常状态和按下状态时按钮图标不同
style = '''
#btn1{
border-radius:4px;
background-image:url('./csdnlogo.jpg');
}
#btn1:Pressed {
background-image:url('./and.png');
}
'''
btn1.setStyleSheet(style)
vbox = QVBoxLayout()
vbox.addWidget(label1)
vbox.addStretch()
vbox.addWidget(btn1)
self.setLayout(vbox)
self.setWindowTitle('使用QSS为标签和按钮添加背景图')
if __name__ == "__main__":
app = QApplication(sys.argv)
form = LabelButtonBackground()
form.show()
sys.exit(app.exec_())
这里报了一个文件找不到的错误 目前还没有解决
QSS文件 style.qss
QMainWindow{ border-image:url(./and.png); } QToolTip{ border:1px solid rgb(45,45,45); background:white; color:red }
装载类 CommonHelper.py
# @CSDN王家视频教程图书馆 # @Time 2022/11/24 20:20 #装载类 class CommonHelper: @staticmethod def readQSS(style): with open(style,'r') as f: return f.read()
loadQSS.py
# @CSDN王家视频教程图书馆 # @Time 2022/11/24 20:21 import sys from PyQt5.QtWidgets import * from CommonHelper import CommonHelper class MainWindow(QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.resize(477, 258) self.setWindowTitle("加载QSS文件") btn = QPushButton() btn.setText('装载QSS文件') # 鼠标放到上面会有提示信息 btn.setToolTip('提示文本') vbox = QVBoxLayout() vbox.addWidget(btn) btn.clicked.connect(self.onClick) self.setLayout(vbox) widget = QWidget(self) self.setCentralWidget(widget) widget.setLayout(vbox) def onClick(self): styleFile = './style.qss' qssStyle = CommonHelper.readQSS(styleFile) win.setStyleSheet(qssStyle) if __name__ == "__main__": app = QApplication(sys.argv) win = MainWindow() win.show() sys.exit(app.exec_())
1. QSS 2. QPalette 3. 直接绘制
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 20:50
'''
使用多种方式设置窗口背景色和背景图片
1. QSS
2. QPalette
3. 直接绘制
'''
import sys
from PyQt5.QtWidgets import *
app = QApplication(sys.argv)
win = QMainWindow()
win.setWindowTitle("背景图片")
win.resize(350, 250)
win.setObjectName("MainWindow")
# 通过QSS动态修改窗口的背景颜色和背景图片
win.setStyleSheet("#MainWindow{border-image:url(./csdnlogo.jpg);}")
#win.setStyleSheet("#MainWindow{background-color:yellow}")
win.show()
sys.exit(app.exec())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 20:54
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
app = QApplication(sys.argv)
win = QMainWindow()
win.setWindowTitle("背景图片")
win.resize(350, 250)
win.setObjectName("MainWindow")
# 通过QPalette设置背景图片和背景颜色
# palette调色板
palette = QPalette()
# 设置画刷
palette.setBrush(QPalette.Background, QBrush(QPixmap("./csdnlogo.jpg")))
# palette.setColor(QPalette.Background,Qt.red)
win.setPalette(palette)
win.show()
sys.exit(app.exec())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 20:57
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
class Background1(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("绘制背景颜色")
def paintEvent(self, event):
painter = QPainter(self)
painter.setBrush(Qt.yellow)
painter.drawRect(self.rect())
if __name__ == "__main__":
app = QApplication(sys.argv)
form = Background1()
form.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 20:58
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
class Background2(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("绘制背景图片")
def paintEvent(self, event):
painter = QPainter(self)
pixmap = QPixmap('./csdnlogo.jpg')
painter.drawPixmap(self.rect(), pixmap)
if __name__ == "__main__":
app = QApplication(sys.argv)
form = Background2()
form.show()
sys.exit(app.exec_())
通过mask实现异形窗口
需要一张透明的png图,透明部分被扣出,形成一个非矩形的区域
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 21:03
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
class AbnormityWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("异形窗口")
self.pix = QBitmap('mask/mask1.png')
self.resize(self.pix.size())
# 设置掩膜,窗口就是掩膜的形状
self.setMask(self.pix)
def paintEvent(self, event):
painter = QPainter(self)
painter.drawPixmap(0, 0, self.pix.width(), self.pix.height(), QPixmap('./csdnlogo.jpg'))
if __name__ == "__main__":
app = QApplication(sys.argv)
form = AbnormityWindow()
form.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 21:26
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
class AbnormityWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("异形窗口")
self.pix = QBitmap('./mask/mask1.png')
self.resize(self.pix.size())
self.setMask(self.pix)
# 鼠标按下
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
# 鼠标按下或抬起标志位
self.m_drag = True
# 当前单击点相对于窗口本身的坐标,永远是正的
self.m_DragPosition = event.globalPos() - self.pos()
# print(self.m_DragPosition)
# 设置光标形状
self.setCursor(QCursor(Qt.OpenHandCursor))
'''
# 当前单击点相对于屏幕的坐标,包括标题栏和边框
print(event.globalPos())
# 当前单击点相对于窗口的坐标,忽略标题栏和边框
print(event.pos())
'''
# 左上角坐标相对于屏幕的坐标,包括标题栏和边框
print(self.pos())
# 按下右键
if event.button() == Qt.RightButton:
self.close()
# 鼠标移动
def mouseMoveEvent(self, QMouseEvent):
if Qt.LeftButton and self.m_drag:
# 当左键移动窗体修改偏移值
# QPoint
'''
实时计算窗口左上角坐标,注意是左上角!!!!!!
这个移动是从上次的窗口位置往现在到达的位置移动,
所以是现在的globalPos()减去移动之前的单击点到窗口边框的距离,就是当前左上角坐标
'''
self.move(QMouseEvent.globalPos() - self.m_DragPosition)
# 鼠标抬起
def mouseReleaseEvent(self, QMouseEvent):
self.m_drag = False
# cursor(n.)光标
self.setCursor(QCursor(Qt.ArrowCursor))
def paintEvent(self, event):
painter = QPainter(self)
painter.drawPixmap(0, 0, self.pix.width(), self.pix.height(), QPixmap('./csdnlogo.jpg'))
if __name__ == "__main__":
app = QApplication(sys.argv)
form = AbnormityWindow()
form.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 21:48
import sys
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtGui import QPixmap, QPainter, QCursor
from PyQt5.QtCore import Qt, QTimer
class AnimationWindows(QWidget):
def __init__(self, parent=None):
super(AnimationWindows, self).__init__(parent)
self.i = 1
self.mypix() # 显示第一张的图
self.timer = QTimer() # 定时器
self.timer.setInterval(500) # 即500毫秒换一帧
self.timer.timeout.connect(self.timeChange)
self.timer.start()
# 显示不规则 pic
def mypix(self):
# 通过立即调用paintEvent()来直接重新绘制窗口部件
self.update()
if self.i == 5:
self.i = 1
self.mypic = {1: './rotate/left.png', 2: "./rotate/top.png", 3: './rotate/right.png',
4: './rotate/buttom.png'}
self.pix = QPixmap(self.mypic[self.i])
self.resize(self.pix.size())
# 设置掩膜
self.setMask(self.pix.mask())
self.dragPosition = None
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.m_drag = True
self.m_DragPosition = event.globalPos() - self.pos()
# 设置光标形状
self.setCursor(QCursor(Qt.OpenHandCursor))
def mouseMoveEvent(self, QMouseEvent):
if Qt.LeftButton and self.m_drag:
self.move(QMouseEvent.globalPos() - self.m_DragPosition)
def mouseReleaseEvent(self, QMouseEvent):
self.m_drag = False
self.setCursor(QCursor(Qt.ArrowCursor))
def paintEvent(self, event):
painter = QPainter(self)
painter.drawPixmap(0, 0, self.pix.width(), self.pix.height(), self.pix)
# 鼠标双击事件
def mouseDoubleClickEvent(self, event):
if event.button() == 1:
self.i += 1
self.mypix()
# 每500毫秒修改paint,即换一张图
def timeChange(self):
self.i += 1
self.mypix()
if __name__ == '__main__':
app = QApplication(sys.argv)
form = AnimationWindows()
form.show()
sys.exit(app.exec_())
效果暂时没有显示出来,后续测试
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 22:08
import sys
from PyQt5.QtWidgets import QApplication,QLabel,QWidget
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QMovie
class loadingGif(QWidget):
def __init__(self):
super(loadingGif, self).__init__()
self.label = QLabel("", self)
self.setFixedSize(128, 128)
self.setWindowFlags(Qt.Dialog | Qt.CustomizeWindowHint)
self.movie = QMovie('../loding2.gif')
self.label.setMovie(self.movie)
self.movie.start()
if __name__ == "__main__":
app = QApplication(sys.argv)
form = loadingGif()
form.show()
sys.exit(app.exec_())
QImage.scaled
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 22:39
from PyQt5.QtWidgets import QApplication, QLabel, QWidget, QVBoxLayout
from PyQt5.QtGui import QImage, QPixmap
from PyQt5.QtCore import Qt
import sys
class ScaleImage(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("图片大小缩放例子")
filename = './csdnlogo.jpg'
img = QImage(filename)
label1 = QLabel(self)
label1.setFixedWidth(200)
label1.setFixedHeight(200)
# 参数三四:忽略比例,平滑显示
result = img.scaled(label1.width(), label1.height(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation)
label1.setPixmap(QPixmap.fromImage(result))
vbox = QVBoxLayout()
vbox.addWidget(label1)
self.setLayout(vbox)
if __name__ == "__main__":
app = QApplication(sys.argv)
win = ScaleImage()
win.show()
sys.exit(app.exec_())
QPropertyAnimation可以控制任何可视控件的尺寸的动态的变化,只要我们把控件的对象通过构造方法传入即可
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 22:48
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
class AnimWindow(QWidget):
def __init__(self):
super(AnimWindow, self).__init__()
self.OrigHeight = 50
self.ChangeHeight = 150
self.setGeometry(QRect(500, 400, 150, self.OrigHeight))
self.btn = QPushButton('展开', self) # 没用布局,直接将按钮放入
self.btn.setGeometry(10, 10, 60, 35)
self.btn.clicked.connect(self.change)
def change(self):
currentHeight = self.height()
if self.OrigHeight == currentHeight:
startHeight = self.OrigHeight
endHeight = self.ChangeHeight
self.btn.setText('收缩')
else:
startHeight = self.ChangeHeight
endHeight = self.OrigHeight
self.btn.setText('展开')
self.animation = QPropertyAnimation(self, b'geometry') # 将当前窗口传入
self.animation.setDuration(500) # 间隔时间:500毫秒
# 初始尺寸
self.animation.setStartValue(QRect(500, 400, 150, startHeight))
# 变化后的尺寸
self.animation.setEndValue(QRect(500, 400, 150, endHeight))
self.animation.start()
return
if __name__ == '__main__':
app = QApplication(sys.argv)
window = AnimWindow()
window.show()
sys.exit(app.exec_())
# @CSDN王家视频教程图书馆
# @Time 2022/11/24 22:55
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
app = QApplication(sys.argv)
window1 = QMainWindow()
window1.show()
window2 = QMainWindow()
window2.show()
animation1 = QPropertyAnimation(window1, b'geometry')
animation2 = QPropertyAnimation(window2, b'geometry')
group = QParallelAnimationGroup() # 并行 动画组 并行,同时运行多个动画
# group = QSequentialAnimationGroup() # 串行
group.addAnimation(animation1)
group.addAnimation(animation2)
animation1.setDuration(3000)
animation1.setStartValue(QRect(0, 0, 100, 30))
animation1.setEndValue(QRect(250, 250, 100, 30))
animation1.setEasingCurve(QEasingCurve.OutBounce) # 动画特效
animation2.setDuration(4000)
animation2.setStartValue(QRect(250, 150, 100, 30))
animation2.setEndValue(QRect(850, 250, 100, 30))
animation2.setEasingCurve(QEasingCurve.CosineCurve)
group.start()
sys.exit(app.exec())
安装:pip3 install pyinstaller
代码:
直接在命令行下操作
常用:pyinstaller -Fw python文件名
pyinstaller -Fw Calc. py
-W:不显示终端
-F:将所有的库打包成-个单独的文件
pip3 install pyinstaller安装
使用pyinstaller查看可选参数
开始打包 pyinstaller -Fw .\ScaleImage.py
打包程序完成
打包成功后项目目录下多了两个文件夹,包括build和dist。exe文件就存在于dist目录下。将文件中调用的文件手动放到exe同目录下。双击exe文件运行即可!
#轻量级数据库,支持多种接口,跨平台
#现在很多移动应用 安卓 iOS 都使用SQLite作为本地数据库
#本地数据库只需要提供文件名,而不需要IP,用户名,密码啥的
#数据库可视化工具DB Browser for SQLite:
#官网:DB Browser for SQLite
#下载:Downloads - DB Browser for SQLite
右键运行生成数据库db文件
QTableView
QSql TableModel
# @CSDN王家视频教程图书馆
# @Time 2022/11/25 0:27
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtSql import *
# 初始化
def initializeModel(model):
model.setTable('people')
# 当字段变化时会触发一些事件
model.setEditStrategy(QSqlTableModel.OnFieldChange)
# 将整个数据装载到model中
model.select()
# 设置字段头
model.setHeaderData(0, Qt.Horizontal, 'ID')
model.setHeaderData(1, Qt.Horizontal, '姓名')
model.setHeaderData(2, Qt.Horizontal, '地址')
# 创建视图
def createView(title, model):
view = QTableView()
view.setModel(model)
view.setWindowTitle(title)
return view
def findrow(i):
# 当前选中的行
delrow = i.row()
print('del row=%s' % str(delrow))
def addrow():
# 不是在QTableView上添加,而是在模型上添加,会自动将数据保存到数据库中!
# 参数一:数据库共有几行数据 参数二:添加几行
ret = model.insertRows(model.rowCount(), 1) # 返回是否插入
print('数据库共有%d行数据' % model.rowCount())
print('insertRow=%s' % str(ret))
if __name__ == '__main__':
app = QApplication(sys.argv)
db = QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName('./db1.db')
model = QSqlTableModel() # MVC模式中的模型
delrow = -1
# 初始化将数据装载到模型当中
initializeModel(model)
view = createView("展示数据", model)
view.clicked.connect(findrow)
dlg = QDialog()
layout = QVBoxLayout()
layout.addWidget(view)
addBtn = QPushButton('添加一行')
addBtn.clicked.connect(addrow)
delBtn = QPushButton('删除一行')
delBtn.clicked.connect(lambda: model.removeRow(view.currentIndex().row()))
layout.addWidget(view)
layout.addWidget(addBtn)
layout.addWidget(delBtn)
dlg.setLayout(layout)
dlg.setWindowTitle("Database Demo")
dlg.resize(500, 400)
dlg.show()
sys.exit(app.exec())
limit关键字
limit n,m
n是起始点(不含),m是偏移量,例如 limit 10,20代表从11开始的20条数据,即11-30
# @CSDN王家视频教程图书馆
# @Time 2022/11/25 0:58
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qt
from PyQt5.QtSql import *
class DataGrid(QWidget):
def createTableAndInit(self):
# 添加数据库
self.db = QSqlDatabase.addDatabase('QSQLITE')
# 设置数据库名称
self.db.setDatabaseName('./database.db')
# 判断是否打开
if not self.db.open():
return False
# 声明数据库查询对象
query = QSqlQuery()
# 创建表
query.exec("create table student(id int primary key, name vchar, sex vchar, age int, deparment vchar)")
# 添加记录
query.exec("insert into student values(1,'张三1','男',20,'计算机')")
query.exec("insert into student values(2,'李四1','男',19,'经管')")
query.exec("insert into student values(3,'王五1','男',22,'机械')")
query.exec("insert into student values(4,'赵六1','男',21,'法律')")
query.exec("insert into student values(5,'小明1','男',20,'英语')")
query.exec("insert into student values(6,'小李1','女',19,'计算机')")
query.exec("insert into student values(7,'小张1','男',20,'机械')")
query.exec("insert into student values(8,'小刚1','男',19,'经管')")
query.exec("insert into student values(9,'张三2','男',21,'计算机')")
query.exec("insert into student values(10,'张三3','女',20,'法律')")
query.exec("insert into student values(11,'王五2','男',19,'经管')")
query.exec("insert into student values(12,'张三4','男',20,'计算机')")
query.exec("insert into student values(13,'小李2','男',20,'机械')")
query.exec("insert into student values(14,'李四2','女',19,'经管')")
query.exec("insert into student values(15,'赵六3','男',21,'英语')")
query.exec("insert into student values(16,'李四2','男',19,'法律')")
query.exec("insert into student values(17,'小张2','女',22,'经管')")
query.exec("insert into student values(18,'李四3','男',21,'英语')")
query.exec("insert into student values(19,'小李3','女',19,'法律')")
query.exec("insert into student values(20,'王五3','女',20,'机械')")
query.exec("insert into student values(21,'张三4','男',22,'计算机')")
query.exec("insert into student values(22,'小李2','男',20,'法律')")
query.exec("insert into student values(23,'张三5','男',19,'经管')")
query.exec("insert into student values(24,'小张3','女',20,'计算机')")
query.exec("insert into student values(25,'李四4','男',22,'英语')")
query.exec("insert into student values(26,'赵六2','男',20,'机械')")
query.exec("insert into student values(27,'小李3','女',19,'英语')")
query.exec("insert into student values(28,'王五4','男',21,'经管')")
return True
def __init__(self):
super().__init__()
self.setWindowTitle("分页查询例子")
self.resize(750, 350)
self.createTableAndInit()
# 当前页
self.currentPage = 0
# 总页数
self.totalPage = 0
# 总记录数
self.totalRecrodCount = 0
# 每页显示记录数
self.PageRecordCount = 6
self.initUI()
def initUI(self):
# 创建窗口
self.createWindow()
# 设置表格
self.setTableView()
# 信号槽连接
self.prevButton.clicked.connect(self.onPrevButtonClick)
self.nextButton.clicked.connect(self.onNextButtonClick)
self.switchPageButton.clicked.connect(self.onSwitchPageButtonClick)
def closeEvent(self, event):
# 关闭数据库
self.db.close()
# 创建窗口
def createWindow(self):
# 操作布局
operatorLayout = QHBoxLayout()
self.prevButton = QPushButton("前一页")
self.nextButton = QPushButton("后一页")
self.switchPageButton = QPushButton("Go")
self.switchPageLineEdit = QLineEdit()
self.switchPageLineEdit.setFixedWidth(40)
switchPage = QLabel("转到第")
page = QLabel("页")
operatorLayout.addWidget(self.prevButton)
operatorLayout.addWidget(self.nextButton)
operatorLayout.addWidget(switchPage)
operatorLayout.addWidget(self.switchPageLineEdit)
operatorLayout.addWidget(page)
operatorLayout.addWidget(self.switchPageButton)
operatorLayout.addWidget(QSplitter())
# 状态布局
statusLayout = QHBoxLayout()
self.totalPageLabel = QLabel()
self.totalPageLabel.setFixedWidth(70)
self.currentPageLabel = QLabel()
self.currentPageLabel.setFixedWidth(70)
self.totalRecordLabel = QLabel()
self.totalRecordLabel.setFixedWidth(70)
statusLayout.addWidget(self.totalPageLabel)
statusLayout.addWidget(self.currentPageLabel)
statusLayout.addWidget(QSplitter())
statusLayout.addWidget(self.totalRecordLabel)
# 设置表格属性
self.tableView = QTableView()
# 表格宽度的自适应调整
self.tableView.horizontalHeader().setStretchLastSection(True)
self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
# 创建界面
mainLayout = QVBoxLayout(self);
mainLayout.addLayout(operatorLayout);
mainLayout.addWidget(self.tableView);
mainLayout.addLayout(statusLayout);
self.setLayout(mainLayout)
# 设置表格
def setTableView(self):
# 声明查询模型
self.queryModel = QSqlQueryModel(self)
# 设置当前页
self.currentPage = 1;
# 得到总记录数
self.totalRecrodCount = self.getTotalRecordCount()
# 得到总页数
self.totalPage = self.getPageCount()
# 刷新状态
self.updateStatus()
# 设置总页数文本
self.setTotalPageLabel()
# 设置总记录数
self.setTotalRecordLabel()
# 记录查询
self.recordQuery(0)
# 设置模型
self.tableView.setModel(self.queryModel)
print('totalRecrodCount=' + str(self.totalRecrodCount))
print('totalPage=' + str(self.totalPage))
# 设置表格表头
self.queryModel.setHeaderData(0, Qt.Horizontal, "编号")
self.queryModel.setHeaderData(1, Qt.Horizontal, "姓名")
self.queryModel.setHeaderData(2, Qt.Horizontal, "性别")
self.queryModel.setHeaderData(3, Qt.Horizontal, "年龄")
self.queryModel.setHeaderData(4, Qt.Horizontal, "院系")
# 得到记录数
def getTotalRecordCount(self):
self.queryModel.setQuery("select * from student")
rowCount = self.queryModel.rowCount()
print('rowCount=' + str(rowCount))
return rowCount
# 得到页数
def getPageCount(self):
if self.totalRecrodCount % self.PageRecordCount == 0:
return (self.totalRecrodCount / self.PageRecordCount)
else:
return (self.totalRecrodCount / self.PageRecordCount + 1)
# 记录查询
def recordQuery(self, limitIndex):
szQuery = ("select * from student limit %d,%d" % (limitIndex, self.PageRecordCount))
print('query sql=' + szQuery)
self.queryModel.setQuery(szQuery)
# 刷新状态
def updateStatus(self):
szCurrentText = ("当前第%d页" % self.currentPage)
self.currentPageLabel.setText(szCurrentText)
# 设置按钮是否可用
if self.currentPage == 1:
self.prevButton.setEnabled(False)
self.nextButton.setEnabled(True)
elif self.currentPage == self.totalPage:
self.prevButton.setEnabled(True)
self.nextButton.setEnabled(False)
else:
self.prevButton.setEnabled(True)
self.nextButton.setEnabled(True)
# 设置总数页文本
def setTotalPageLabel(self):
szPageCountText = ("总共%d页" % self.totalPage)
self.totalPageLabel.setText(szPageCountText)
# 设置总记录数
def setTotalRecordLabel(self):
szTotalRecordText = ("共%d条" % self.totalRecrodCount)
print('*** setTotalRecordLabel szTotalRecordText=' + szTotalRecordText)
self.totalRecordLabel.setText(szTotalRecordText)
# 前一页按钮按下
def onPrevButtonClick(self):
print('*** onPrevButtonClick ');
limitIndex = (self.currentPage - 2) * self.PageRecordCount
self.recordQuery(limitIndex)
self.currentPage -= 1
self.updateStatus()
# 后一页按钮按下
def onNextButtonClick(self):
print('*** onNextButtonClick ');
limitIndex = self.currentPage * self.PageRecordCount
self.recordQuery(limitIndex)
self.currentPage += 1
self.updateStatus()
# 转到页按钮按下
def onSwitchPageButtonClick(self):
# 得到输入字符串
szText = self.switchPageLineEdit.text()
# 得到页数
pageIndex = int(szText)
# 判断是否有指定页
if pageIndex > self.totalPage or pageIndex < 1:
QMessageBox.information(self, "提示", "没有指定的页面,请重新输入")
return
# 得到查询起始行号
limitIndex = (pageIndex - 1) * self.PageRecordCount
# 记录查询
self.recordQuery(limitIndex);
# 设置当前页
self.currentPage = pageIndex
# 刷新状态
self.updateStatus();
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建窗口
example = DataGrid()
# 显示窗口
example.show()
sys.exit(app.exec_())
首先安装 pip3 install pyqtgraph
pyqtgraph_pyqt.py
# @CSDN王家视频教程图书馆 # @Time 2022/11/25 1:15 # -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'pyqtgraph_pyqt.ui' # # Created by: PyQt5 UI code generator 5.9.2 # # WARNING! All changes made in this file will be lost! from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(800, 600) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.pyqtgraph1 = GraphicsLayoutWidget(self.centralwidget) self.pyqtgraph1.setGeometry(QtCore.QRect(10, 10, 721, 251)) self.pyqtgraph1.setObjectName("pyqtgraph1") self.pyqtgraph2 = GraphicsLayoutWidget(self.centralwidget) self.pyqtgraph2.setGeometry(QtCore.QRect(10, 290, 501, 281)) self.pyqtgraph2.setObjectName("pyqtgraph2") MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22)) 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")) from pyqtgraph import GraphicsLayoutWidget
Graph.py
# @CSDN王家视频教程图书馆 # @Time 2022/11/25 1:16 ''' 使用PyQtGraph绘图 pip Install pyqtgraph ''' from PyQt5.QtCore import pyqtSlot from PyQt5.QtWidgets import QMainWindow, QApplication import pyqtgraph as pg from pyqtgraph_pyqt import Ui_MainWindow import numpy as np class MainWindow(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) pg.setConfigOption('background', '#f0f0f0') pg.setConfigOption('foreground', 'd') self.setupUi(self) self.draw1() self.draw2() def draw1(self): self.pyqtgraph1.clear() '''第一种绘图方式''' print(np.random.normal(size=120)) self.pyqtgraph1.addPlot(title="绘图单条线", y=np.random.normal(size=120), pen=pg.mkPen(color='b', width=2)) '''第二种绘图方式''' plt2 = self.pyqtgraph1.addPlot(title='绘制多条线') plt2.plot(np.random.normal(size=150), pen=pg.mkPen(color='r', width=2), name="Red curve") plt2.plot(np.random.normal(size=110) + 5, pen=(0, 255, 0), name="Green curve") plt2.plot(np.random.normal(size=120) + 10, pen=(0, 0, 255), name="Blue curve") def draw2(self): plt = self.pyqtgraph2.addPlot(title='绘制条状图') x = np.arange(10) print(x) y1 = np.sin(x) y2 = 1.1 * np.sin(x + 1) y3 = 1.2 * np.sin(x + 2) bg1 = pg.BarGraphItem(x=x, height=y1, width=0.3, brush='r') bg2 = pg.BarGraphItem(x=x + 0.33, height=y2, width=0.3, brush='g') bg3 = pg.BarGraphItem(x=x + 0.66, height=y3, width=0.3, brush='b') plt.addItem(bg1) plt.addItem(bg2) plt.addItem(bg3) self.pyqtgraph2.nextRow() p4 = self.pyqtgraph2.addPlot(title="参数图+显示网格") x = np.cos(np.linspace(0, 2 * np.pi, 1000)) y = np.sin(np.linspace(0, 4 * np.pi, 1000)) p4.plot(x, y, pen=pg.mkPen(color='d', width=2)) # p4.showGrid(x=True, y=True) # 显示网格 if __name__ == "__main__": import sys app = QApplication(sys.argv) ui = MainWindow() ui.show() sys.exit(app.exec_())