PyQt制作二维码生成器
一、Python图形化工具
如果用 Python
语言开发跨平台的图形界面的程序,主要有3种选择:
-
Tkinter
基于Tk的Python库,这是Python官方采用的标准库,优点是作为Python标准库、稳定、发布程序较小,缺点是控件相对较少。
-
wxPython
基于wxWidgets的Python库,优点是控件比较丰富,缺点是稳定性相对差点、文档少、用户少。
-
PySide2、PyQt5
基于Qt 的Python库,优点是控件比较丰富、跨平台体验好、文档完善、用户多。
缺点是 库比较大,发布出来的程序比较大。
二、PySide2、PyQt5简介
PySide2、PyQt5 都是基于著名的 Qt 库。
Qt库里面有非常强大的图形界面开发库,但是Qt库是C++语言开发的,PySide2、PyQt5可以让我们通过Python语言使用Qt。
PySide2、PyQt5 两者的区别:
PySide2 是Qt的亲儿子, PyQt5 是Qt还没有亲儿子之前的收的义子(Riverbank Computing这个公司开发的)。
三、环境配置
1、使用镜像安装pyside2
pip install pyside2 -i https://pypi.douban.com/simple/
2、安装qrcode、pillow
pip install pillow
pip install qrcode
两个都必须安装,如果只安装qrcode不行。
四、QRcode相关概念
1、什么是QRcode
QR 码是二维条码的一种,QR来自英文 “Quick Response” 的缩写,即快速反应的意思。 与之前的条形码相比,QR 码能存储更丰富的信息,包括对文字、URL 地址和其他类型的数据加密。
QR码的结构, 根据标准(ISO/IEC 18004),了解到 QR 码结构如下:
2、qrcode的使用
import qrcode
qr = qrcode.QRCode(
version=1, # 版本号,越大生成的二维码越复杂,存储的信息越多。
error_correction=qrcode.constants.ERROR_CORRECT_L, # 控制纠错水平,L、M、Q、H,从左到右依次增加
box_size=10, # 设置每个方块二维码的像素
border=4, # 设置二维码的边界
)
qr.add_data('Some data') # 二维码中的信息
qr.make(fit=True) # 自动调节
img = qr.make_image(fill_color="black", back_color="white") # 设置二维码颜色
img.show() # 展示生成的二维码
img.save("mycode.png") # 保存生成的二维码
五、界面设计师Qt Designer
1、Qt Designer简介
QT程序界面的 一个个窗口、控件,就是像上面那样用相应的代码创建出来的。
使用QT界面生成器QT Designer,通过拖拉就可以直接创建出程序界面,非常方便。
在Windows系统中,在你的Python安装目录下 Scripts\pyside2-designer.exe 这个可执行文件
运行界面如下:
保存之后会生成 .ui文件,打开就是一个XML格式的界面定义。
2、动态加载UI文件
有了界面定义的ui文件,python程序就可以从文件中加载ui定义,并动态创建一个相应的窗口对象。
代码如下:
from PySide2.QtWidgets import QApplication, QMessageBox
from PySide2.QtUiTools import QUiLoader
class Stats:
def __init__(self):
# 从文件中加载UI定义
# 从 UI 定义中动态 创建一个相应的窗口对象
# 注意:里面的控件对象也成为窗口对象的属性了
# 比如 self.ui.button、self.ui.textEdit
self.ui = QUiLoader().load('main.ui')
def handleCalc(self):
info = self.ui.textEdit.toPlainText()
app = QApplication([])
stats = Stats()
stats.ui.show()
app.exec_()
六、常用控件
1、按钮
`QPushButton` 就是常见的按钮
- 信号:被点击时
当按钮被点击就会发出 clicked
信号,可以这样指定处理该信号的函数。
button.clicked.connect(handleCalc)
- 改变文本
可以使用setText方法改变按钮文本。
button.setText(text)
- 设置图标
可以通过一下方法给按钮设置图标。
from PySide2.QtCore import Qt,QSize
from PySide2.QtGui import QIcon
# 设置图标
button.setIcon(QIcon('logo.png'))
# 设置图标大小
button.setIconSize(QSize(30, 30))
2、单行文本框
QLineEdit
是只能单行编辑的文本框。
- 信号:文本被修改
当文本框中的内容被键盘编辑,被点击就会发出 textChanged 信号,可以这样指定处理该信号的函数
edit.textChanged.connect(handleTextChange)
Qt在调用这个信号处理函数时,传入的参数就是 文本框目前的内容字符串。
- 信号:按下回车键
当用户在文本框中任何时候按下回车键,就会发出 returnPressed信号。
有时我们需要处理这种情况,比如登录界面,用户输完密码直接按回车键就进行登录处理,比再用鼠标点击登录按钮快捷的多。可以指定处理 returnPressed 信号,如下所示:
passwordEdit.returnPressed.connect(onLogin)
- 获取文本内容
通过 text
方法获取编辑框内的文本内容。
text = edit.text()
- 设置提示
通过 setPlaceholderText
方法可以设置提示文本内容。
edit.setPlaceholderText('请在这里输入内容')
- 设置文本
通过 setText
方法设置编辑框内的文本内容为参数里面的文本字符串。
edit.setText('你好!')
3、多行文本框
QPlainTextEdit
是可以多行的纯文本编辑框。
- 信号:文本被修改
edit.textChanged.connect(handleTextChange)
注意: Qt在调用这个信号处理函数时,不会传入文本框目前的内容字符串,作为参数。这个行为和单行文本框不同。
- 获取文本
通过 toPlainText
方法获取编辑框内的文本内容。
text = edit.toPlainText()
- 设置文本
通过 setPlainText
方法设置编辑框内的文本内容 为参数里面的文本字符串。
edit.setPlainText('''你好呀!''')
注意: 原有的所有内容会被清除。
- 设置提示
通过 setPlaceholderText
方法可以设置提示文本内容。
edit.setPlaceholderText('请在这里输入内容')
- 在末尾添加文本
通过 appendPlainText
方法在编辑框末尾添加文本内容。
edit.appendPlainText('你好,白月黑羽')
**注意:**这种方法会在添加文本后自动换行
- 设置最大行数
有时候,代码会不断往文本框添加内容,为了防止占用过多资源,可以设置文本框最大行数。
edit.document().setMaximumBlockCount(100)
最大行数为100行。
4、文本浏览框
QTextBrowser
是只能查看文本控件。
通常用来显示一些操作日志信息、或者不需要用户编辑的大段文本内容。
该控件获取文本、设置文本、清除文本、剪贴板复制粘贴 等等, 都和上面介绍的多行纯文本框是一样的。
在末尾添加文本
通过 append
方法在编辑框末尾添加文本内容
textBrowser.append('hello')
5、组合选择框
QComboBox
是组合选择框,如下图所示
-
信号:选项改变
如果用户操作修改了QComboBox中的选项就会发出
currentIndexChanged
信号,可以这样指定处理该信号的函数。
cbox.currentIndexChanged.connect(handleSelectionChange)
- 添加选项
代码中可以使用 addItem
方法来添加一个选项到 末尾
,参数就是选项文本。
cbox.addItem('red')
代码中可以使用 addItems
方法来添加多个选项到末尾,参数是包含了多个选项文本的列表。
cbox.addItems(['black','red','yellow'])
- 获取当前选项文本
代码中可以使用 currentText
方法来获取当前选中的选项的文本。
color = cbox.currentText()
6、单选按钮和按钮组
QRadioButton
是单选按钮
同一个父窗口里面的多个单选按钮,只能选中一项。
如果你有多组单选按钮, 每组都应该有不同的父控件,或者不同的Layout。
通常建议:多组单选按钮,放到不同的 按钮组 QButtonGroup
中
-
信号:选中状态改变
如果用户操作点击了按钮组
QButtonGroup
中的一个按钮, QButtonGroup 就会发出buttonClicked
信号,可以这样指定处理该信号的函数
buttongroup.buttonClicked.connect(handleButtonClicked)
然后,在处理函数中调用QButtonGroup对象的 checkedButton()
函数,返回值就是被选中的按钮对象。
再调用这个返回的按钮对象的 text()
方法得到界面文本,就可以知道是哪个选项被选中了。
7、Tab页控件
我们可以通过tab页控件把界面分为好几个页面。
实现效果:
- Tab页中布局Layout
如果我们要在tab页上布局, 你可能会在对象查看器总直接右键点击该tab,可以你会发现右键菜单里面没有布局项。
-
首先需要你在tab页上添加一个控件
-
然后点击 在对象查看器 右键点击上层 TabWidget ,这时,你就会发现有布局菜单了
8、数字输入框
QSpinBox
是数字输入框,可以输入或使用上下箭头选择数字。
-
获取数字
通过
value
方法获取编辑框内的文本内容。
number = box.value()
**注意:**返回的是整数对象,不是字符串。
- 设置数字
通过 setValue
方法可以设置提示文本内容。
box.setValue(10)
9、选择文件框
QFileDialog
类可以用来选择文件或者目录
-
选择单个文件
如果你想弹出文件选择框,选择一个已经存在的文件,可以使用QFileDialog静态方法
getOpenFileName
。
from PySide2.QtWidgets import QFileDialog
filePath = QFileDialog.getOpenFileName(
self.ui, # 父窗口对象
"选择你要上传的图片", # 标题
"d:", # 起始目录
"图片类型 (*.png *.jpg *.bmp)" # 选择类型过滤项,过滤内容在括号中
)
该方法返回值 是一个元组,第一个元素是选择的文件路径,第二个元素是文件类型,如果你只想获取文件路径即可,可以采用上面的代码写法。
如果用户点击了 选择框的 取消选择按钮,返回空字符串。
如果你想弹出文件选择框,选择路径和文件名,来保存一个文件,可以使用QFileDialog静态方法 `getSaveFileName` 。
from PySide2.QtWidgets import QFileDialog
filePath = QFileDialog.getSaveFileName(
self.ui, # 父窗口对象
"保存文件", # 标题
"d:\\data", # 起始目录
"json类型 (*.json)" # 选择类型过滤项,过滤内容在括号中
)
- 选择多个文件
如果要选择多个文件,使用 getOpenFileNames
静态方法。
from PySide2.QtWidgets import QFileDialog
filePaths = QFileDialog.getOpenFileNames(
self.ui, # 父窗口对象
"选择你要上传的图片", # 标题
"d:", # 起始目录
"图片类型 (*.png *.jpg *.bmp)" # 选择类型过滤项,过滤内容在括号中
)
上例中 filePaths 对应的返回值是一个列表,里面包含了选择的文件。
如果用户点击了选择框的取消选择按钮,返回空列表。
10、提示框
QMessageBox
类可以用来弹出各种提示框。
- 错误提示
使用 critical
方法
QMessageBox.critical(
self.ui,
'错误',
'请输入正确数据!')
- 警告提示
使用 warning
方法
QMessageBox.warning(
self.ui,
'阅读太快',
'阅读客户协议必须超过1分钟')
-
信息提示
使用
information
方法
QMessageBox.information(
self.ui,
'操作成功',
'请继续下一步操作')
-
确认提示
使用
question
方法
choice = QMessageBox.question(
self.ui,
'确认',
'确定要删除本文件吗?')
if choice == QMessageBox.Yes:
print('你选择了yes')
if choice == QMessageBox.No:
print('你选择了no')
七、项目展示
1、项目截图
2、项目代码
from PySide2.QtWidgets import QApplication, QMessageBox, QRadioButton, QFileDialog
from PySide2.QtUiTools import QUiLoader
import qrcode
from PIL import Image
class Stats:
def __init__(self):
# 从文件中加载UI定义
# 从 UI 定义中动态 创建一个相应的窗口对象
# 注意:里面的控件对象也成为窗口对象的属性了
# 比如 self.ui.button , self.ui.textEdit
self.ui = QUiLoader().load('main.ui')
self.ui.comboBox.addItems(['黑', '红', '绿', '黄']) # 添加下拉框内容
self.ui.pushButton_1.clicked.connect(self.openFile)
self.ui.pushButton_2.clicked.connect(self.createQRCode)
# 退出按钮
self.ui.pushButton_3.clicked.connect(self.exit)
# 生成二维码按钮
def createQRCode(self):
# 获取内容
size = self.ui.lineEdit_1.text() # 单行文本框
icon_ptah = self.ui.lineEdit_2.text() # 照片路径
colour = self.ui.comboBox.currentText() # 下拉框
info = self.ui.textEdit.toPlainText() # 文本框
if size == "":
QMessageBox.about(self.ui, "提示", "尺寸不能为空!")
elif 0 >= int(size) or int(size) > 40:
QMessageBox.about(self.ui, "提示", "输入正确范围数据!")
else:
# 生成二维码
# 创建QRCode对象
qr = qrcode.QRCode(
version=int(size), # 大小
error_correction=qrcode.constants.ERROR_CORRECT_H, # 纠错等级
box_size=10,
border=4
)
qr.add_data(info) # 添加信息,info为二维码中的信息
qr.make(fit=True) # 自适应信息大小
# 二维码颜色
if colour == "红":
img = qr.make_image(fill_color="red")
elif colour == "黄":
img = qr.make_image(fill_color="yellow")
elif colour == "绿":
img = qr.make_image(fill_color="green")
else:
img = qr.make_image()
img = img.convert("RGBA")
if icon_ptah != "":
icon = Image.open(icon_ptah) # 这里是二维码中心的图片
img_w, img_h = img.size
factor = 4
size_w = int(img_w / factor)
size_h = int(img_h / factor)
# 设置照片大小并将照片放在中心位置
icon_w, icon_h = icon.size
if icon_w > size_w:
icon_w = size_w
if icon_h > size_h:
icon_h = size_h
icon = icon.resize((icon_w, icon_h), Image.ANTIALIAS)
w = int((img_w - icon_w) / 2)
h = int((img_h - icon_h) / 2)
icon = icon.convert("RGBA") # 转换icon格式
img.paste(icon, (w, h), icon) # 将icon粘贴到二维码图像
img.show() # 显示图片
# img.save("qrcode.png") # 保存照片
#打开文件按钮
def openFile(self):
fname = QFileDialog.getOpenFileName(
self.ui, # 父窗口对象
"选择你要上传的图片", # 标题
"d:", # 起始目录
"图片类型 (*.png *.jpg *.bmp)" # 选择类型过滤项,过滤内容在括号中
)
self.ui.lineEdit_2.setText(fname[0]) # 将文件路径输入到单行文本框中
# 退出按钮
def exit(self):
app.exit()
# 主程序
if __name__ == '__main__':
app = QApplication([])
stats = Stats()
stats.ui.show()
app.exec_()