1, Write at the beginning
Boring writing. Recently, I learned how to do python GUI. I feel much behind the web page. I just want to finish the task assigned by the teacher and do a small program to cooperate with ZBar to scan the barcode. I don't intend to go deep into the QR code or anything. Because pyqt5 seems not very popular, there are not many systematic tutorials. All I can find is http://code.py40.com/pyqt5/ This website. Don't look next to each other, slide to the bottom to show you the code
Let's take a look at the previous picture
It can't be simpler, but it's a bit stumbling for the first time
Tools: pycharm + qt Designer + pyUIC
The main function of qt Designer is to make a graphical interface
The main function of pyUIC is to translate graphic interface into. py file
The main functions are as follows: scanning pictures with external program ZBar, exporting data to excel with xlwt library, and other pyqt5 operations such as selecting files and changing ico icons
2, Installation of tools
Install pyqt5
pip install pyqt5
Install pyqt5 tools
pip install pyqt5-tools
After that, qt designer will be installed in your python root directory under \ lib \ site packages \ pyqt5 \ tools \ QT \ bin \
The next step is to configure pycharm s
File->settings->Tools->External Tools->+
Configure qt designer
Configure pyUIC
Parameters: - M pyqt5.uic.pyuic $filename $- o $filenamewithoutextension $. PY
Location of tools:
Now the tool has been installed
3, Run the first helloword (warm up)
pycharmnew a python project
Tools->External Tools->Qt Designer
Create a Main Window template (I created a dialog for the first time, but I can't run it)
Display Widgets, the left toolbar, drag a Label to the middle of the window and quietly tap Helloworld
Right click HelloWorld - > change stylesheet
This should be the css you are familiar with. We see that the words are a little out of bounds. Here is a little trick
Right click helloword - > layout - > adjust size
At this time, Helloworld is full
Ctrl+S save to project folder
Left click to select helloworld.ui (be sure to select it). pyUIC, the search tool, clicks to automatically generate the helloworld.py file
Create a new main.py file as the main entry in the project directory, separate it from the code of the graphical interface (it's convenient to try), and type the following code:
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() # Logic code sys.exit(app.exec_())
Run main.py
4, Installing ZBar
https://sourceforge.net/projects/zbar/files/zbar/0.10/zbar-0.10-setup.exe/download
Install to your project's directory
Go to the ZBar/bin / directory and open the console here
Prepare a bar code picture (there is a bar code in the ZBar/example directory)
Scan it out and it's successful. Another zbarcam.exe under bin / is used to scan the barcode in the video
5, Interface
Tools->External Tools->Qt Desginer
Create a Main Window
Set up the interface first
Buttons - > push button drag out two buttons
Item Widgets - > Table widget drag two table boxes
Display Widgets - > label drag label
Number of files: and 0 are two different labels
Next, start to name each component. You need to know the meaning of the name
Check the import button and name it importBtn
one by one
Save to the project directory as barcode. UI - > left click to select - > tools - > external tools - > pyuic
Get the code of barcode.py GUI
6, Trigger
First, import barcode.py module in main.py file, and change barcode module to generate ui object
There are two object ui objects and MainWindow objects
You can manage buttons, labels and other components through ui objects, and close windows through MainWindow
Trigger event by clicking button
Write the simplest exit button first
# 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() # Logic code ui.exitBtn.clicked.connect(lambda: exitEvent(mw)) sys.exit(app.exec_())
ui.exitBtn.clicked.connect(lambda: exitEvent(mw)) lambda expression is used here to solve the problem of parameter passing. There is also a partial parameter passing method. Pass the main window object of mw to exitEvent() function, operate the object of mw, realize modularization of operation, such as adding an exit confirmation box
Run main.py and click exit to exit the interface
7, Select file
Open barcode.ui, double-click the first table box to write out the fields
Then click save and directly convert to barcode.py file with pyUIC. This is the benefit of separation, just interface, regardless of logic.
We can learn how this table injects data by observing barcode.py, such as this paragraph
# def setupUi() item = QtWidgets.QTableWidgetItem() self.fileList.setItem(0, 0, item) # Generate a cell at (0,0)
# def retranslateUi() item = self.fileList.item(0, 0) item.setText(_translate("MainWindow", "1")) # Inject the character 1 at (0,0)
As you can see, the setupUi() method focuses on creation, while the retranslateUi() method focuses on injection of data, just like the building, we build the framework first, and then add bricks and tiles in it
from PyQt5 import QtCore, QtGui import barcode import sys import time import os from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog, QMessageBox, QTableWidgetItem # File collection, make sure elements are not duplicated fileSet = set() # method def importEvent(mw, ui): files = QFileDialog.getOpenFileNames(mw, 'Open file', './', ("Images (*.png *.jpg *.bmp *.gif *.raw *.tif *.xpm)")) for i in files[0]: fileSet.add(i) ui.totalFileNum.setText(str(len(fileSet))) # Total files ui.fileList.clearContents() ui.fileList.setRowCount(0) for file in fileSet: row = ui.fileList.rowCount() ui.fileList.insertRow(row) # file name fileNameItem = QTableWidgetItem(os.path.basename(file)) fileNameItem.setTextAlignment(QtCore.Qt.AlignCenter) # file size fileSizeItem = QTableWidgetItem(str("%.2f" % (os.path.getsize(file) / 1024)) + "KB") fileSizeItem.setTextAlignment(QtCore.Qt.AlignCenter) # File absolute path filePathItem = QTableWidgetItem(file) filePathItem.setTextAlignment(QtCore.Qt.AlignCenter) # File creation time createTimeItem = QTableWidgetItem(timeStampToStrTime(os.path.getctime(file))) createTimeItem.setTextAlignment(QtCore.Qt.AlignCenter) # File modification time 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): """Exit event""" mw.close() if __name__ == "__main__": app = QApplication(sys.argv) mw = QMainWindow() ui = barcode.Ui_MainWindow() ui.setupUi(mw) mw.show() # Principal code # Field display width 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) # Button ui.importBtn.clicked.connect(lambda: importEvent(mw, ui)) # Import button ui.exitBtn.clicked.connect(lambda: exitEvent(mw)) # Exit button sys.exit(app.exec_())
Here we use the file selector. To use QFileDialog.getOpenFileNames(), press and hold Ctrl to select multiple files. Don't use getOpenfileName() to select only one file at a time.
The returned files are a tuple ([file 1 absolute path, file 2 absolute path,...], file type)
files[0] returns the absolute path of the selected file. With the absolute path, it is easy to work. The file name, size, creation time and other attributes can be obtained from os.path
Create an absolute path for the collection fileSet to save files, so you are not afraid to select duplicate files
("Images (*.png *.jpg *.bmp *.gif *.raw *.tif *.xpm)") is the limitation of file type. Without this parameter, you can add any file
Every time a new file is added, the original table content will be cleared and the line number will be set to 0
ui.fileList.clearContents() ui.fileList.setRowCount(0)
There is nothing else to say. Some basic property operations of pyqt components
Run main.py
8, Scan events
Open barcode.ui, double-click the second table to write out the fields in turn
from PyQt5 import QtCore, QtGui import barcode import sys import time import os from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog, QMessageBox, QTableWidgetItem # File collection, make sure elements are not duplicated fileSet = set() # method def importEvent(mw, ui): files = QFileDialog.getOpenFileNames(mw, 'Open file', './', ("Images (*.png *.jpg *.bmp *.gif *.raw *.tif *.xpm)")) if !files: return for i in files[0]: fileSet.add(i) ui.totalFile.setText(str(len(fileSet))) # Total files ui.fileList.clearContents() ui.fileList.setRowCount(0) for file in fileSet: row = ui.fileList.rowCount() ui.fileList.insertRow(row) # file name fileNameItem = QTableWidgetItem(os.path.basename(file)) fileNameItem.setTextAlignment(QtCore.Qt.AlignCenter) # file size fileSizeItem = QTableWidgetItem(str("%.2f" % (os.path.getsize(file) / 1024)) + "KB") fileSizeItem.setTextAlignment(QtCore.Qt.AlignCenter) # File absolute path filePathItem = QTableWidgetItem(file) filePathItem.setTextAlignment(QtCore.Qt.AlignCenter) # File creation time createTimeItem = QTableWidgetItem(timeToStrTime(os.path.getctime(file))) createTimeItem.setTextAlignment(QtCore.Qt.AlignCenter) # File modification time modifyTimeItem = QTableWidgetItem(timeToStrTime(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 timeToStrTime(timestamp): """Convert timestamps to format time strings""" timeStruct = time.localtime(timestamp) return time.strftime('%Y-%m-%d %H:%M', timeStruct) def startScan(mw, ui): if len(fileSet) == 0: QMessageBox.information(mw, 'Tips', 'You have not selected any barcode image file!', QMessageBox.Ok, QMessageBox.Ok) return successCount = 0 # Number of successful tests failCount = 0 # Number of failed tests cmd = ".\\ZBar\\bin\\zbarimg.exe " ui.resultList.clearContents() ui.resultList.setRowCount(0) for file in fileSet: array = execCmd(cmd + file) # Execute the command. \ zbarimg.exe imgPath row = ui.resultList.rowCount() ui.resultList.insertRow(row) fileNameItem = QTableWidgetItem(os.path.basename(file)) fileNameItem.setTextAlignment(QtCore.Qt.AlignCenter) if len(array) == 0: # Setting failed red font statusItem = QTableWidgetItem("Scan failed") statusItem.setTextAlignment(QtCore.Qt.AlignCenter) brush = QtGui.QBrush(QtGui.QColor(234, 31, 42)) brush.setStyle(QtCore.Qt.NoBrush) statusItem.setForeground(brush) typeItem = QTableWidgetItem("Please adjust the picture definition") typeItem.setTextAlignment(QtCore.Qt.AlignCenter) brush = QtGui.QBrush(QtGui.QColor(234, 31, 42)) brush.setStyle(QtCore.Qt.NoBrush) typeItem.setForeground(brush) valueItem = QTableWidgetItem("Please adjust the picture definition") valueItem.setTextAlignment(QtCore.Qt.AlignCenter) brush = QtGui.QBrush(QtGui.QColor(234, 31, 42)) brush.setStyle(QtCore.Qt.NoBrush) valueItem.setForeground(brush) failCount += 1 else: # Set successful green font statusItem = QTableWidgetItem("Scan successful") statusItem.setTextAlignment(QtCore.Qt.AlignCenter) brush = QtGui.QBrush(QtGui.QColor(35, 177, 32)) brush.setStyle(QtCore.Qt.NoBrush) statusItem.setForeground(brush) result = array[0].split(":") # Separating strings to get barcode format and content codebarType = result[0] # Barcode format codebarValue = result[1].strip() # Bar code content, remove the space at both ends, tab trim() function typeItem = QTableWidgetItem(codebarType) typeItem.setTextAlignment(QtCore.Qt.AlignCenter) valueItem = QTableWidgetItem(codebarValue) valueItem.setTextAlignment(QtCore.Qt.AlignCenter) successCount += 1 ui.resultList.setItem(row, 0, fileNameItem) ui.resultList.setItem(row, 1, statusItem) ui.resultList.setItem(row, 2, typeItem) ui.resultList.setItem(row, 3, valueItem) ui.successScanNum.setText(str(successCount)) # Set the number of files scanned successfully ui.failScanNum.setText(str(failCount)) def exitEvent(mw): """Exit event""" mw.close() def execCmd(cmd): """Execute console commands""" result = os.popen(cmd) text = result.readlines() result.close() return text if __name__ == "__main__": app = QApplication(sys.argv) mw = QMainWindow() ui = barcode.Ui_MainWindow() ui.setupUi(mw) mw.show() # Principal code # Field display width 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) # Button ui.scanBtn.clicked.connect(lambda: startScan(mw, ui)) # Scan button ui.importBtn.clicked.connect(lambda: importEvent(mw, ui)) # Import button ui.exitBtn.clicked.connect(lambda: exitEvent(mw)) # Exit button sys.exit(app.exec_())
Execute the console instruction through execCmd(). cmd = ".\ZBar\bin\zbarimg.exe" is the ZBar/bin/zbarimg.exe program under the current target run by main.py. As long as the absolute path of a picture is appended, the scanning operation can be realized. Note that there is a space directly between zbarimg.exe and the absolute path of the picture. execCmd() obtains the result by executing the command, loads the result into memory, and then separates each string. The text of the return of the scan result is a list, in which only one element is the scan result, or there is no element that does not scan the result. It can be easily determined
Run main.py
9, Import to excel
Using xlwt modules
pip install xlwt
# main.py def exportEvent(mw, ui): """Save to excel""" if len(fileSet) == 0: QMessageBox.information(mw, 'Tips', 'You have not selected any barcode image file!', QMessageBox.Ok, QMessageBox.Ok) return # Create a workbook to set the encoding workbook = xlwt.Workbook(encoding='utf-8') # Create a worksheet worksheet = workbook.add_sheet('sheet1') # style t = xlwt.Font() t.colour_index = 10 # Red font redColorFont = xlwt.XFStyle() redColorFont.font = t t = xlwt.Font() t.colour_index = 57 # Green font greenColorFont = xlwt.XFStyle() greenColorFont.font = t # Parameter corresponding row, column, value worksheet.write(0, 0, label='file name') worksheet.col(0).width = 256 * 20 worksheet.write(0, 1, label='Scan status') worksheet.write(0, 2, label='format') worksheet.write(0, 3, label='value') worksheet.col(3).width = 256 * 20 worksheet.write(0, 4, label='File path') worksheet.col(4).width = 256 * 80 cmd = ".\\ZBar\\bin\\zbarimg.exe " row = 1 for file in fileSet: worksheet.write(row, 0, label=os.path.basename(file)) array = execCmd(cmd + file) if len(array) == 0: worksheet.write(row, 1, u'Scan failed', redColorFont) else: worksheet.write(row, 1, u'Scan successful', greenColorFont) result = array[0].split(":") worksheet.write(row, 2, label=result[0]) worksheet.write(row, 3, label=result[1].strip()) worksheet.write(row, 4, label=file) row += 1 # preservation workbook.save('.\\data.xls')
# main.py from PyQt5 import QtCore, QtGui import barcode import sys import time import xlwt import os from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog, QMessageBox, QTableWidgetItem # File collection, make sure elements are not duplicated fileSet = set() # method def importEvent(mw, ui): files = QFileDialog.getOpenFileNames(mw, 'Open file', './', ("Images (*.png *.jpg *.bmp *.gif *.raw *.tif *.xpm)")) if not files[0]: return for i in files[0]: fileSet.add(i) ui.totalFileNum.setText(str(len(fileSet))) # Total files ui.fileList.clearContents() ui.fileList.setRowCount(0) for file in fileSet: row = ui.fileList.rowCount() ui.fileList.insertRow(row) # file name fileNameItem = QTableWidgetItem(os.path.basename(file)) fileNameItem.setTextAlignment(QtCore.Qt.AlignCenter) # file size fileSizeItem = QTableWidgetItem(str("%.2f" % (os.path.getsize(file) / 1024)) + "KB") fileSizeItem.setTextAlignment(QtCore.Qt.AlignCenter) # File absolute path filePathItem = QTableWidgetItem(file) filePathItem.setTextAlignment(QtCore.Qt.AlignCenter) # File creation time createTimeItem = QTableWidgetItem(timeToStrTime(os.path.getctime(file))) createTimeItem.setTextAlignment(QtCore.Qt.AlignCenter) # File modification time modifyTimeItem = QTableWidgetItem(timeToStrTime(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 timeToStrTime(timestamp): """Convert timestamps to format time strings""" timeStruct = time.localtime(timestamp) return time.strftime('%Y-%m-%d %H:%M', timeStruct) def startScan(mw, ui): if len(fileSet) == 0: QMessageBox.information(mw, 'Tips', 'You have not selected any barcode image file!', QMessageBox.Ok, QMessageBox.Ok) return successCount = 0 # Number of successful tests failCount = 0 # Number of failed tests cmd = ".\\ZBar\\bin\\zbarimg.exe " ui.resultList.clearContents() ui.resultList.setRowCount(0) for file in fileSet: array = execCmd(cmd + file) # Execute the command. \ zbarimg.exe imgPath row = ui.resultList.rowCount() ui.resultList.insertRow(row) fileNameItem = QTableWidgetItem(os.path.basename(file)) fileNameItem.setTextAlignment(QtCore.Qt.AlignCenter) if len(array) == 0: # Setting failed red font statusItem = QTableWidgetItem("Scan failed") statusItem.setTextAlignment(QtCore.Qt.AlignCenter) brush = QtGui.QBrush(QtGui.QColor(234, 31, 42)) brush.setStyle(QtCore.Qt.NoBrush) statusItem.setForeground(brush) typeItem = QTableWidgetItem("Please adjust the picture definition") typeItem.setTextAlignment(QtCore.Qt.AlignCenter) brush = QtGui.QBrush(QtGui.QColor(234, 31, 42)) brush.setStyle(QtCore.Qt.NoBrush) typeItem.setForeground(brush) valueItem = QTableWidgetItem("Please adjust the picture definition") valueItem.setTextAlignment(QtCore.Qt.AlignCenter) brush = QtGui.QBrush(QtGui.QColor(234, 31, 42)) brush.setStyle(QtCore.Qt.NoBrush) valueItem.setForeground(brush) failCount += 1 else: # Set successful green font statusItem = QTableWidgetItem("Scan successful") statusItem.setTextAlignment(QtCore.Qt.AlignCenter) brush = QtGui.QBrush(QtGui.QColor(35, 177, 32)) brush.setStyle(QtCore.Qt.NoBrush) statusItem.setForeground(brush) result = array[0].split(":") # Separating strings to get barcode format and content codebarType = result[0] # Barcode format codebarValue = result[1].strip() # Bar code content, remove the space at both ends, tab trim() function typeItem = QTableWidgetItem(codebarType) typeItem.setTextAlignment(QtCore.Qt.AlignCenter) valueItem = QTableWidgetItem(codebarValue) valueItem.setTextAlignment(QtCore.Qt.AlignCenter) successCount += 1 ui.resultList.setItem(row, 0, fileNameItem) ui.resultList.setItem(row, 1, statusItem) ui.resultList.setItem(row, 2, typeItem) ui.resultList.setItem(row, 3, valueItem) ui.successScanNum.setText(str(successCount)) # Set the number of files scanned successfully ui.failScanNum.setText(str(failCount)) def exportEvent(mw, ui): """Save to excel""" if len(fileSet) == 0: QMessageBox.information(mw, 'Tips', 'You have not selected any barcode image file!', QMessageBox.Ok, QMessageBox.Ok) return # Create a workbook to set the encoding workbook = xlwt.Workbook(encoding='utf-8') # Create a worksheet worksheet = workbook.add_sheet('sheet1') # style t = xlwt.Font() t.colour_index = 10 # Red font redColorFont = xlwt.XFStyle() redColorFont.font = t t = xlwt.Font() t.colour_index = 57 # Green font greenColorFont = xlwt.XFStyle() greenColorFont.font = t # Parameter corresponding row, column, value worksheet.write(0, 0, label='file name') worksheet.col(0).width = 256 * 20 worksheet.write(0, 1, label='Scan status') worksheet.write(0, 2, label='format') worksheet.write(0, 3, label='value') worksheet.col(3).width = 256 * 20 worksheet.write(0, 4, label='File path') worksheet.col(4).width = 256 * 80 cmd = ".\\ZBar\\bin\\zbarimg.exe " row = 1 for file in fileSet: worksheet.write(row, 0, label=os.path.basename(file)) array = execCmd(cmd + file) if len(array) == 0: worksheet.write(row, 1, u'Scan failed', redColorFont) else: worksheet.write(row, 1, u'Scan successful', greenColorFont) result = array[0].split(":") worksheet.write(row, 2, label=result[0]) worksheet.write(row, 3, label=result[1].strip()) worksheet.write(row, 4, label=file) row += 1 # preservation workbook.save('.\\data.xls') def exitEvent(mw): """Exit event""" mw.close() def execCmd(cmd): """Execute console commands""" result = os.popen(cmd) text = result.readlines() result.close() return text if __name__ == "__main__": app = QApplication(sys.argv) mw = QMainWindow() ui = barcode.Ui_MainWindow() ui.setupUi(mw) mw.show() # Principal code # Field display width 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) # Button ui.exportBtn.clicked.connect(lambda: exportEvent(mw, ui)) # Export button ui.scanBtn.clicked.connect(lambda: startScan(mw, ui)) # Scan button ui.importBtn.clicked.connect(lambda: importEvent(mw, ui)) # Import button ui.exitBtn.clicked.connect(lambda: exitEvent(mw)) # Exit button sys.exit(app.exec_())
run main.py
Good operation
The above is the record on the python GUI. To be honest, it's really unnecessary. Is Django not fragrant? Is vue not fragrant
Source code is here https://github.com/CaseyFu/python/tree/master/src/GUI/barcode