pyqt5入门练习-扫描条形码(一)
问题
使用pyqt5, Qt Designer, PyUIC, pycharm, ZBar练习python GUI开发, 扫描条形码案例
最近学习做python GUI开发, 为了完成老师布置的任务, 做一个配合ZBar扫描条形码的小程序, 不打算过多深究二维码什么的
我能找到的教程就是http://code.py40.com/pyqt5/这个网站, 但是这个教材没有使用qt designer, 前期给了我很大的困惑
先上一张图, 看看效果
简单得不能再简单了, 但第一次写有点磕磕绊绊的
- 工具:pycharm + qt Designer + pyUIC + ZBar
qt Designer
的主要功能就是把图形界面做出来pyUIC
的主要功能就是把图形界面翻译成.py文件ZBar
的功能是扫描图片上的条形码
主要实现的功能有: 用外部程序ZBar扫描图片、用xlwt库导出数据到excel, pyinstaller打包python文件, 其它的就是pyqt5的一些操作比如选择文件、换ico图标之类的
工具的安装
安装pyqt5 pip install pyqt5
安装pyqt5-tools pip install pyqt5-tools
完成了之后qt designer就安装在你的python根目录下的\Lib\site-packages\pyqt5_tools\Qt\bin\下
配置pycharm File->settings->Tools->External Tools->+
配置qt designer
配置pyUIC
参数:-m PyQt5.uic.pyuic $FileName$ -o $FileNameWithoutExtension$.py
工具的位置:
安装ZBar
https://sourceforge.net/projects/zbar/files/zbar/0.10/zbar-0.10-setup.exe/download
安装到你项目的目录中, 进入ZBar/bin/
目录, 在此处打开控制台, 准备一张条形码图片(ZBar/example目录中有一张条形码)
执行命令zbarimg.exe ../examples/barcode.png
扫描出来就证明成功了, bin/下的另一个zbarcam.exe是用来扫视频中的条形码的
运行第一个Helloworld
pycharm new一个python项目出来
Tools->External Tools->Qt Designer
创建一个Main Window模板(我第一次创建了个对话框, 怎么也运行不了, 血的代价)
左边工具栏Display Widgets拖一个Label到窗口中间, 安静地敲下Helloworld
右击HelloWorld->change styleSheet
这是你熟悉的css, 我们看到字有点超出边界了, 这里有个小技巧
右击Helloword->Layout->Adjust Size
这时候Helloworld饱满了
Ctrl+S保存到项目文件夹
左键选中helloworld.ui(一定要选中) 寻找工具pyUIC 点击 自动生成了helloworld.py文件
在项目目录中新建main.py文件作为主入口, 与图形界面的代码分离(试过就知道很方便), 并敲下如下代码:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow
import helloworld
if __name__ == "__main__":
app = QApplication(sys.argv)
mw = QMainWindow()
ui = helloworld.Ui_MainWindow()
ui.setupUi(mw)
mw.show()
# 逻辑代码
sys.exit(app.exec_())
运行main.py
界面制作
Tools->External Tools->Qt Desginer
创建一个Main Window 先把界面摆好
Buttons->Push Button拖出两个按钮
Item Widgets->Table Widget拖出两个表格框
Display Widgets->Label拖出标签
文件数:
和0
是两个不同标签
接下来开始为每个组件命名, 要做到见名知意
选中导入按钮命名为importBtn
依次地
保存到项目目录为barcode.ui->左键点击选中->Tools->External Tools->pyUIC
得到barcode.py 图形界面的代码
触发按钮
首先在main.py文件中进口barcode.py模块, 更改barcode模块生成ui对象
有两个对象ui对象和MainWindow对象
通过ui对象可以管理按钮、标签等组件, 通过MainWindow可以进行关闭窗口等操作
通过点击按钮 触发事件
先写最简单的退出按钮
# main.py
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow
import barcode
def exitEvent(mw):
mw.close()
if __name__ == "__main__":
app = QApplication(sys.argv)
mw = QMainWindow()
ui = barcode.Ui_MainWindow()
ui.setupUi(mw)
mw.show()
# 逻辑代码
ui.exitBtn.clicked.connect(lambda: exitEvent(mw))
sys.exit(app.exec_())
ui.exitBtn.clicked.connect(lambda: exitEvent(mw))
这里使用lambda表达式主要是为了解决传参问题,还有一种partial传参方式没lambda好用。把mw主窗口对象传递到exitEvent()函数中, 对mw对象进行操作, 实现操作的模块化, 比如加个退出的确认框呀什么的
运行main.py 点击退出按钮 退出界面
选择文件
打开barcode.ui 双击第一个表格框 写出各个字段
然后点击保存, 直接用pyUIC转换成barcode.py文件, 这就是分离的好处, 只管界面, 不管逻辑。
我们可以通过观察barcode.py学习这个表格是怎么注入数据的, 如这一段
# def setupUi()
item = QtWidgets.QTableWidgetItem()
self.fileList.setItem(0, 0, item)
# 在(0,0)位置处生成一个单元格
# def retranslateUi()
item = self.fileList.item(0, 0)
item.setText(_translate("MainWindow", "1"))
# 在(0,0)处注入1这个字符
可以看到setupUi()方法专注于创建, 而retranslateUi()方法专注于注入数据, 就像盖楼一样, 我们先把框架搭好, 然后再在里面添砖加瓦
from PyQt5 import QtCore, QtGui
import barcode
import sys
import time
import os
from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog, QMessageBox, QTableWidgetItem
# 文件集合, 保存选择的文件的绝对路径, 确保元素不重复
fileSet = set()
# method
def importEvent(mw, ui):
files = QFileDialog.getOpenFileNames(mw, '打开文件', './', ("Images (*.png *.jpg *.bmp *.gif *.raw *.tif *.xpm)"))
for i in files[0]:
fileSet.add(i)
ui.totalFileNum.setText(str(len(fileSet))) # 文件总数
ui.fileList.clearContents()
ui.fileList.setRowCount(0)
for file in fileSet:
row = ui.fileList.rowCount()
ui.fileList.insertRow(row)
# 文件名
fileNameItem = QTableWidgetItem(os.path.basename(file))
fileNameItem.setTextAlignment(QtCore.Qt.AlignCenter)
# 文件大小
fileSizeItem = QTableWidgetItem(str("%.2f" % (os.path.getsize(file) / 1024)) + "KB")
fileSizeItem.setTextAlignment(QtCore.Qt.AlignCenter)
# 文件绝对路径
filePathItem = QTableWidgetItem(file)
filePathItem.setTextAlignment(QtCore.Qt.AlignCenter)
# 文件创建时间
createTimeItem = QTableWidgetItem(timeStampToStrTime(os.path.getctime(file)))
createTimeItem.setTextAlignment(QtCore.Qt.AlignCenter)
# 文件修改时间
modifyTimeItem = QTableWidgetItem(timeStampToStrTime(os.path.getmtime(file)))
modifyTimeItem.setTextAlignment(QtCore.Qt.AlignCenter)
ui.fileList.setItem(row, 0, fileNameItem)
ui.fileList.setItem(row, 1, fileSizeItem)
ui.fileList.setItem(row, 2, filePathItem)
ui.fileList.setItem(row, 3, createTimeItem)
ui.fileList.setItem(row, 4, modifyTimeItem)
def exitEvent(mw):
"""退出事件"""
mw.close()
if __name__ == "__main__":
app = QApplication(sys.argv)
mw = QMainWindow()
ui = barcode.Ui_MainWindow()
ui.setupUi(mw)
mw.show()
# 主体代码
# 字段显示宽度
ui.fileList.setColumnWidth(0, 150)
ui.fileList.setColumnWidth(1, 150)
ui.fileList.setColumnWidth(2, 500)
ui.fileList.setColumnWidth(3, 200)
ui.fileList.setColumnWidth(4, 200)
ui.resultList.setColumnWidth(0, 150)
ui.resultList.setColumnWidth(1, 150)
ui.resultList.setColumnWidth(2, 400)
ui.resultList.setColumnWidth(3, 400)
# 按钮
ui.importBtn.clicked.connect(lambda: importEvent(mw, ui)) # 导入按钮
ui.exitBtn.clicked.connect(lambda: exitEvent(mw)) # 退出按钮
sys.exit(app.exec_())
-
这里用到文件选择器, 要用QFileDialog.getOpenFileNames(), 按住Ctrl可以选择多个文件。 别用getOpenfileName()这个一次只能选择一个文件。
-
返回的files是一个元组, ([文件1绝对路径, 文件2绝对路径, ...], 文件类型)
files[0]返回的是选中的文件的绝对路径, 有了绝对路径就好办事了, 文件名、大小、创建时间等属性可以由os.path得到 -
创建一个集合fileSet用于保存文件的绝对路径, 这样就不怕选择了重复的文件
-
("Images (*.png *.jpg *.bmp *.gif *.raw *.tif *.xpm)")是对文件类型的限制, 去掉这个参数就是可以添加任何文件
每次新加入文件就把原来的表格内容清空同时行号置0
ui.fileList.clearContents()
ui.fileList.setRowCount(0)
运行main.py