PyQt5实战之二维码生成器(二):控件功能实现

前言

经过上一章,我们构建了二维码生成器的基本界面,本章将实现界面中各个控件的功能。

一、工具箱的数据输入

创建一个 getQR() 方法用于生成二维码,每次生成二维码时需要对传入的参数进行验证。

def getQR(self): # 生成二维码
    data_flag = self.toolBox.currentIndex() # 数据类型(所选栏目)
    data = ''
    if data_flag == 0: # URL
        data = self.lineEdit_url.text()
    elif data_flag == 1: # TEXT
        data = self.textEdit.toPlainText()
    elif data_flag == 2: # CARD
        name = self.lineEdit_name.text()
        tel = self.lineEdit_tel.text()
        qq = self.lineEdit_qq.text()
        mail = self.lineEdit_mail.text()
        company = self.lineEdit_company.text()
        website = self.lineEdit_website.text()
        data = f'MECARD:N:{name};ORG:{company};TEL:{tel};EMAIL:{mail};URL:{website};NOTE:QQ :{qq};' # MECARD格式的电子名片
    color = self.color_now # 颜色
    imagepath = self.lineEdit_filepath.text() # 图片路径
    depth = float(self.slider_depth.value())/100 # 透明度
    filetype = imagepath[imagepath.rfind('.'):].lower() # 文件后缀小写
    path = imagepath[:imagepath.rfind('.')] + filetype # 重置路径
    # 执行生成二维码 ------
    try:
        pass
    except:
        pass

首先,通过 data_flag 变量来确定用户当前选择了工具箱中的哪一个抽屉,即选择输入哪种数据。接着,根据用户选择,单行文本框通过 text() 方法,多行文本框通过 toPlainText() 方法获取用户输入值。

data_flag = self.toolBox.currentIndex() # 数据类型(所选栏目)
data = ''
if data_flag == 0: # URL
    data = self.lineEdit_url.text()
elif data_flag == 1: # TEXT
    data = self.textEdit.toPlainText()

需要注意的是,当用户选择 CARD 一栏时,笔者采用的是 MECARD 格式的电子名片,其为日本的 docomo 公司制定的一种数据格式,是互联网中一种规范的文件传播格式,它的主要作用是转化传统纸质商业名片上的信息。

elif data_flag == 2: # CARD
    name = self.lineEdit_name.text()
    tel = self.lineEdit_tel.text()
    qq = self.lineEdit_qq.text()
    mail = self.lineEdit_mail.text()
    company = self.lineEdit_company.text()
    website = self.lineEdit_website.text()
    data = f'MECARD:N:{name};ORG:{company};TEL:{tel};EMAIL:{mail};URL:{website};NOTE:QQ :{qq};' # MECARD格式的电子名片

手机扫码后效果如下:
在这里插入图片描述
然后,获取颜色、图片路径、透明度等参数。self.color_now 为自行添加的类成员变量,用于保存用户当前选择的颜色,默认值为 ‘#000000’ ,即黑色。而生成带背景图的二维码采用的是 MyQR 库,通过调整亮度和对比度可以改变图片的透明度,其所需参数为 float 类型,故用 depth 变量保存用户选择的透明度。最后再对读入图像的路径做一下调整即可。

color = self.color_now # 颜色
depth = float(self.slider_depth.value())/100 # 透明度
imagepath = self.lineEdit_filepath.text() # 图片路径
filetype = imagepath[imagepath.rfind('.'):].lower() # 文件后缀小写
path = imagepath[:imagepath.rfind('.')] + filetype # 重置路径

如下样例图,根据用户的选择,可以生成 logo 和背景图两种模式的二维码。生成二维码的具体方式将在后续的章节中详细说明。
在这里插入图片描述

二、颜色选项卡

点击各个颜色按钮时,需要实现 3 个动作。首先设置当前用户选择的颜色(修改self.color_now 的值),接着将单选按钮设为选中 logo 按钮(因选择背景图时前景色限制为黑色),最后调用 getQR() 方法。注意:本次采用的是按钮的 pressed 信号而非 clicked 信号,区别在于前者为按下,后者为按下并抬起。

for n in range (0,8): # 颜色按钮被点击时更改颜色代码, 同时修改单项按钮为logo项,并执行生成 ->
    getattr(self, 'pb_%s'%n).pressed.connect(lambda c = n : self.setColor(c))
    getattr(self, 'pb_%s' % n).pressed.connect(self.change2logo)
    getattr(self, 'pb_%s'%n).pressed.connect(self.getQR)

在这里插入图片描述
下面来看两个槽函数, setColor() 为带参数的方法,接收按钮的序号,即颜色列表的索引, 之后在颜色代码文本框中显示当前颜色代码。

def setColor(self,c): # 设置默认颜色按钮
    self.color_now = self.color_list[c]
    self.lineEdit_color_code.setText(self.color_now)

change2logo() 方法将 logo 的单选按钮设为选中。

def change2logo(self): # 选中logo项
    self.radioButton_0.setChecked(True)

除了使用预设的颜色,用户也可以选择输入其他颜色代码,所以给 Enter 按钮绑定一个槽函数,手动修改自定义的颜色。

def set_myColor(self): # 手动设置颜色代码
    if self.lineEdit_color_code.text() != "":
        self.color_now = self.lineEdit_color_code.text()
    self.getQR()

不要忘记这里也需要再选中 logo 的单选按钮。目的是当用户选择背景图模式时,能通过选择颜色直接切换为 logo 模式,无需再通过单选按钮。

self.pb_color_enter.clicked.connect(self.change2logo)
self.pb_color_enter.clicked.connect(self.set_myColor) # 点击Enter按钮设置颜色,同时修改单项按钮为logo项,并并执行生成

三、图像选项卡

生成二维码所需的图像参数为图像的路径,利用 QFileDialog.getOpenFileName() 方法即可获取文件路径,之后再将路径显示在路径文本框中即可,限定仅可选择 png、jpg、gif 三种格式的图片。

def openFile(self): # 打开图片文件
    filepath, filetype = QFileDialog.getOpenFileName(self, self.tr('Choose image'), './', '(*.png);;(*.jpg);;(*.gif)')
    self.lineEdit_filepath.setText(filepath)

在这里插入图片描述
当选择背景图模式时,可以对背景图的透明度进行调整。笔者采用滑块的方式来调整,先设置滑块的默认值为100,即正常图像。然后添加刻度以便观察。因为不需要太精确的微调,故设置步长为10,即每次通过点击进行的改动值为10(拖动仍可微调)。

self.slider_depth.setValue(100)  # 滑块默认值100
self.slider_depth.setTickPosition(QSlider.TicksAbove) # 设置刻度的位置,刻度在下方
self.slider_depth.setTickInterval(20) # 设置刻度的间隔
self.slider_depth.setSingleStep(10)

在拖动滑块的同时,希望在旁边的标签能够显示透明度的值,所以为值变化信号绑定一个槽函数。

self.slider_depth.valueChanged.connect(self.setDepth)

setDepth() 方法首先获取滑块的值,再将其转化为百分比的格式,嵌入到描述文本中。

def setDepth(self): # 显示图片透明度
    d = self.slider_depth.value()
    self.label_depth.setText(' Depth:' + ' '*(3-len(str(d))) + '%s%%'%d)

如此,便实现了选项卡中基本的参数设置需求。

四、菜单栏

菜单栏中有4项功能,分别为其触发信号绑定各自的槽函数。

self.actionSave_as.triggered.connect(self.saveAs) # 菜单栏-另存为
self.actionAbout.triggered.connect(self.about) # 菜单栏-关于
self.actionChinese.triggered.connect(self.trans_cn) # 菜单栏-汉化
self.actionEnglish.triggered.connect(self.trans_en)  # 菜单栏-英化

另存为:生成的二维码默认文件名为“ test_qr ”,保存在根目录,故另存为的时候从根目录读入图像,再按用户指定路径保存即可。

def saveAs(self): # 另存为
    try:
        img = Image.open('test_qr.png')
        filepath, filetype = QFileDialog.getSaveFileName(self, self.tr("Save QRcode image as"),'test_qr.png', '(*.png);;(*.gif)')
        img.save(filepath)
    except:
        QMessageBox.about(self,self.tr('Remind'),self.tr('No new QR code generated !'))

关于:自定义一个 Dialog 窗体,弹窗对象需使用 exec() 方法等待响应。

def about(self): # 关于窗口
    d = QDialog()
    d.setWindowTitle(self.tr('About'))
    d.resize(110,70)
    hbox = QtWidgets.QHBoxLayout()
    hbox.addWidget(QtWidgets.QLabel(self.tr('This tool is created by @ Seon_ Pan\nUsed to generate custom QR code\nLearn and reference only')))
    d.setLayout(hbox)
    d.show()
    d.exec()

在这里插入图片描述

英汉互译的部分将在之后的国际化章节详细说明。

五、状态栏

状态栏显示信息效果如下:
在这里插入图片描述
为测试状态栏的功能,本次笔者仅利用状态栏显示4段信息,分别是点击工具箱的4个抽屉时的提示说明。先为工具箱的选项变化信号绑定一个槽函数。

self.toolBox.currentChanged.connect(self.show_status) # 选择不同栏目时在状态栏显示说明信息

选择不同的的抽屉栏时,在状态栏中显示对应的信息。

def show_status(self):
    data_flag = self.toolBox.currentIndex()  # 数据类型(所选栏目)
    if data_flag == 0:  # URL
        msg = self.tr(' ---> Explain: Input the link address according to the format')
    elif data_flag == 1:  # TEXT
        msg = self.tr(' ---> Explain: Input unformatted text')
    elif data_flag == 2:  # CARD
        msg = self.tr(' ---> Explain: Electronic business card in MECARD format')
    elif data_flag == 3:  # HTML
        msg = self.tr(' ---> Explain: The function has not been realized yet...')
    self.statusbar.showMessage(msg,4600)

六、回顾 __init__()

在进入核心功能代码之前,再来回顾一下界面设置,和各类控件的动作信号绑定槽函数的情况。

def __init__(self):
    super(MaForm, self).__init__()
    self.setupUi(self)
    # 图标 ------------------------------------------------------------
    self.toolBox.setItemIcon(0,QIcon(":resource/url.ico"))
    self.toolBox.setItemIcon(1, QIcon(":resource/text.ico"))
    self.toolBox.setItemIcon(2, QIcon(":resource/card.ico"))
    self.toolBox.setItemIcon(3, QIcon(":resource/html.ico"))
    self.pb_clean_text.setIcon(QIcon(":resource/x.ico"))
    self.pb_clean_text.setStyleSheet("border:none;")
    # 参数 ------------------------------------------------------------
    self.color_list = ['#000000', '#DC143C', '#FFA500', '#FFD700', '#90EE90',
                       '#40E0D0', '#00BFFF','#BA55D3']  # 颜色列表
    self.color_now = '#000000' # 默认为黑色
    self.edit_list = ['lineEdit_url', 'lineEdit_name', 'lineEdit_tel', 'lineEdit_qq', 'lineEdit_mail',
                        'lineEdit_company', 'lineEdit_website', 'lineEdit_color_code', 'lineEdit_filepath',
                        ]  # 文本框列表
    # 界面控件设置 ----------------------------------------------------------
    palette = QPalette()
    palette.setColor(QPalette.Window, Qt.white)
    self.label_result.setAutoFillBackground(True)
    self.label_result.setPalette(palette) # 设置结果图区域的label为白色背景
    self.slider_depth.setValue(100)  # 滑块默认值100
    self.slider_depth.setTickPosition(QSlider.TicksAbove) # 设置刻度的位置,刻度在下方
    self.slider_depth.setSingleStep(10)
    self.slider_depth.setTickInterval(20) # 设置刻度的间隔
    for n in range (0,len(self.edit_list)): # 设置文本框清空提示,多行文本无该功能
        getattr(self, self.edit_list[n]).setClearButtonEnabled(True)
    for n in range (0,len(self.color_list)): # 设置按钮颜色
        getattr(self, 'pb_%s'%n).setStyleSheet("background-color: " + self.color_list[n])
    # 连接槽函数 -----------------------------------------------------------
    self.pb_clean_text.clicked.connect(self.clean_words) # 清空多行文本
    self.textEdit.textChanged.connect(self.show_words) # 显示字数
    self.pb_openfile.clicked.connect(self.openFile) # 打开图片
    self.slider_depth.valueChanged.connect(self.setDepth) # 更改透明度
    self.pb_color_enter.clicked.connect(self.change2logo)
    self.pb_color_enter.clicked.connect(self.set_myColor) # 点击Enter按钮设置颜色,同时修改单选按钮为logo项,并执行生成 ->
    for n in range (0,8): # 颜色按钮被点击时更改颜色代码, 同时修改单项按钮为logo项,并执行生成 ->
        getattr(self, 'pb_%s'%n).pressed.connect(lambda c = n : self.setColor(c))
        getattr(self, 'pb_%s' % n).pressed.connect(self.change2logo)
        getattr(self, 'pb_%s'%n).pressed.connect(self.getQR)
    self.actionSave_as.triggered.connect(self.saveAs) # 菜单栏-另存为
    self.actionAbout.triggered.connect(self.about) # 菜单栏-关于
    self.actionChinese.triggered.connect(self.trans_cn) # 菜单栏-汉化
    self.actionEnglish.triggered.connect(self.trans_en)  # 菜单栏-英化
    self.toolBox.currentChanged.connect(self.show_status) # 选择不同栏目时在状态栏显示说明信息

可以注意到,目前在颜色选项卡中点击颜色按钮和 Enter 按钮时会执行 getQR() 方法生成二维码,还有哪些情况需要执行呢?需要尽可能地简化用户操作,即每当用户想对二维码的样式或内容进行修改时,就执行生成二维码的操作,无需将【生成】这一动作单独拿出来,它应该结合到每一次【修改】动作中。

因此,笔者设置每一个文本框被修改时,就执行生成。但由于多行文本输入内容造成的修改较为频繁,每次执行间隔时间太短,可能会造成界面卡顿,故为其单独设置一个生成按钮,在用户确定完成输入后,再点击生成。此外,在释放滑块的时候执行生成(注意不是在拖动的时候执行),是因为拖动时值的变化更为频繁,也会造成界面卡顿。当然界面卡顿的问题,还可以靠多线程解决。

然后在 logo 和 背景图单选按钮选择改变时,也执行生成以便在两种图像模式切换时快速得到结果。

self.slider_depth.sliderReleased.connect(self.getQR) # 释放滑块时执行生成 ->
self.radioButton_0.toggled.connect(self.getQR) # 单选按钮切换时执行生成 ->
self.pb_getQR.clicked.connect(self.getQR) # 多行文本框下方的按钮
for i in range(0, len(self.edit_list)): # 文本框被修改时执行生成 ->
    getattr(self, self.edit_list[i]).textChanged.connect(self.getQR)

七、本章小结

第二章我们实现了各个控件的基本功能,例如数据输入、选择颜色、打开图像、菜单栏动作、状态栏信息等内容。下一章将继续讲解定制化二维码,包括修改二维码颜色、添加 logo 图片或背景图片、调节背景图透明度等操作,敬请关注!

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值