問題
使用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
