引言
使用pyqt5,Qt Designer,PyUIC,pycharm,ZBar练习python GUI开发,扫描条形码案例。无聊写写。最近学习做python GUI开发, 感觉比网页落后好多。我只是为了完成老师布置的任务, 做一个配合ZBar扫描条形码的小程序, 不打算过多深究二维码什么的, 感觉没什么意义。由于pyqt5貌似不是很火, 没多少成系统的教程。我能找到的就是http://code.py40.com/pyqt5/这个网站, 但是没有配合qt designer使用前期给了我很大的困惑。滑到最下面show you the code
先上一张图, 看看效果
简单得不能再简单了, 但第一次写有点磕磕绊绊的
- 工具: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根目录下的Libsite-packagespyqt5_toolsQtin
下 - 配置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
目录中有一张条形码)
扫描出来就证明成功了, bin/下的另一个zbarcam.exe是用来扫视频中的条形码的
二、运行第一个Helloworld
pycharmnew
一个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